bitkeeper revision 1.22.2.7 (3e4540ce236_3mBFvJr9jn3-rPO3sA)
authoriap10@labyrinth.cl.cam.ac.uk <iap10@labyrinth.cl.cam.ac.uk>
Sat, 8 Feb 2003 17:39:26 +0000 (17:39 +0000)
committeriap10@labyrinth.cl.cam.ac.uk <iap10@labyrinth.cl.cam.ac.uk>
Sat, 8 Feb 2003 17:39:26 +0000 (17:39 +0000)
Support (untested) for Intel E1000 driver. This required adding a
bunch of new linux headers, and a fair bit of tidying. It correctly
detects the card, but I haven't sent/received any packets.

23 files changed:
.rootkeys
xen-2.4.16/arch/i386/process.c
xen-2.4.16/drivers/net/Makefile
xen-2.4.16/drivers/net/e1000/LICENSE [new file with mode: 0644]
xen-2.4.16/drivers/net/e1000/Makefile [new file with mode: 0644]
xen-2.4.16/drivers/net/e1000/e1000.h [new file with mode: 0644]
xen-2.4.16/drivers/net/e1000/e1000_ethtool.c [new file with mode: 0644]
xen-2.4.16/drivers/net/e1000/e1000_hw.c [new file with mode: 0644]
xen-2.4.16/drivers/net/e1000/e1000_hw.h [new file with mode: 0644]
xen-2.4.16/drivers/net/e1000/e1000_main.c [new file with mode: 0644]
xen-2.4.16/drivers/net/e1000/e1000_osdep.h [new file with mode: 0644]
xen-2.4.16/drivers/net/e1000/e1000_param.c [new file with mode: 0644]
xen-2.4.16/drivers/pci/pci.c
xen-2.4.16/include/asm-i386/irq.h
xen-2.4.16/include/asm-i386/uaccess.h
xen-2.4.16/include/xeno/ethtool.h
xen-2.4.16/include/xeno/if_vlan.h [new file with mode: 0644]
xen-2.4.16/include/xeno/kernel.h [new file with mode: 0644]
xen-2.4.16/include/xeno/netdevice.h
xen-2.4.16/include/xeno/notifier.h [new file with mode: 0644]
xen-2.4.16/include/xeno/pci.h
xen-2.4.16/include/xeno/reboot.h [new file with mode: 0644]
xen-2.4.16/include/xeno/types.h

index 741ebc6331606bc2542a6216b9c6eb5f86665936..b0ee9fa0a7ce890c98f9f8e563a37a348596cc44 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 3ddb79bfLVGtyXNJS4NQg-lP21rndA xen-2.4.16/drivers/net/8139too.c
 3ddb79c0tWiE8xIFHszxipeVCGKTSA xen-2.4.16/drivers/net/Makefile
 3ddb79bfU-H1Hms4BuJEPPydjXUEaQ xen-2.4.16/drivers/net/Space.c
+3e4540ccS4bfbx9rLiLElP0F1OVwZA xen-2.4.16/drivers/net/e1000/LICENSE
+3e4540ccXG6af_6-u0IiKKvtdGHJyA xen-2.4.16/drivers/net/e1000/Makefile
+3e4540ccoY2eo4VIkbR4sCOj0bVzSA xen-2.4.16/drivers/net/e1000/e1000.h
+3e4540ccvUz0j2ejQ9Z9djEGc93wRA xen-2.4.16/drivers/net/e1000/e1000_ethtool.c
+3e4540ccjqsc94nU3C4w3ZJaxFZFjA xen-2.4.16/drivers/net/e1000/e1000_hw.c
+3e4540cczrrQVyyj-s1-viyX1kMUlA xen-2.4.16/drivers/net/e1000/e1000_hw.h
+3e4540ccvQ9Dtoh9tV-L3ULUwN9X7g xen-2.4.16/drivers/net/e1000/e1000_main.c
+3e4540cc3t7_y-YLeyMG2pX9xtdXPA xen-2.4.16/drivers/net/e1000/e1000_osdep.h
+3e4540cct_8Ig-Y1W_vM2gS_u7mC0A xen-2.4.16/drivers/net/e1000/e1000_param.c
 3ddb79c0GejJrp1U6W4G6dYi-RiH4A xen-2.4.16/drivers/net/eepro100.c
 3ddb79bfKvn9mt0kofpkw0QaWjxO6A xen-2.4.16/drivers/net/net_init.c
 3ddb79c0fQgORkFlqWZdP-6cDHyFIQ xen-2.4.16/drivers/net/pcnet32.c
 3ddb79c1yHLp08JhgPxIMcZ8DwN9hg xen-2.4.16/include/xeno/if.h
 3ddb79c1RCWOkWPQRzbYVTX_e-E7CA xen-2.4.16/include/xeno/if_ether.h
 3ddb79c2IYah7z7hkzPyOiG8szKkyw xen-2.4.16/include/xeno/if_packet.h
+3e4540ccefnCkeqtD_dW_CBOjXUSYw xen-2.4.16/include/xeno/if_vlan.h
 3df0af1c-QrOEqpPHq4uL3NZzCeJCg xen-2.4.16/include/xeno/in.h
 3ddb79c0GurNF9tDWqQbAwJFH8ugfA xen-2.4.16/include/xeno/init.h
 3ddb79c1Vi5VleJAOKHAlY0G2zAsgw xen-2.4.16/include/xeno/interrupt.h
 3ddb79c2qAxCOABlkKtD8Txohe-qEw xen-2.4.16/include/xeno/irq.h
 3ddb79c2b3qe-6Ann09FqZBF4IrJaQ xen-2.4.16/include/xeno/irq_cpustat.h
 3ddb79c11w_O7z7YZJnzuDSxaK5LlA xen-2.4.16/include/xeno/kdev_t.h
+3e4540ccPHqIIv2pvnQ1gV8LUnoHIg xen-2.4.16/include/xeno/kernel.h
 3ddb79c1NfYlOrWNqgZkj9EwtFfJow xen-2.4.16/include/xeno/lib.h
 3ddb79c18Ajy7micDGQQfJ0zWgEHtA xen-2.4.16/include/xeno/list.h
 3ddb79c0_s2_wgV0cA6tztEaeyy1NA xen-2.4.16/include/xeno/major.h
 3ddb79c13p9iHn1XAp0IS1qvj4yDsg xen-2.4.16/include/xeno/module.h
 3ddb79c1ieLZfGSFwfvvSQ2NK1BMSg xen-2.4.16/include/xeno/multiboot.h
 3ddb79c0CLfAlJLg1ohdPD-Jjn-jxg xen-2.4.16/include/xeno/netdevice.h
+3e4540ccaugeWGdOuphJKj6WFw1jkw xen-2.4.16/include/xeno/notifier.h
 3ddb79c2Fg44_PBPVxHSC0gTOMq4Ow xen-2.4.16/include/xeno/pci.h
 3ddb79c0MOVXq8qZDQRGb6z64_xAwg xen-2.4.16/include/xeno/pci_ids.h
 3ddb79c2byJwwNNkiES__A9H4Cvc4g xen-2.4.16/include/xeno/pkt_sched.h
 3ddb79c04nQVR3EYM5L4zxDV_MCo1g xen-2.4.16/include/xeno/prefetch.h
+3e4540ccU1sgCx8seIMGlahmMfv7yQ xen-2.4.16/include/xeno/reboot.h
 3ddb79c0LzqqS0LhAQ50ekgj4oGl7Q xen-2.4.16/include/xeno/sched.h
 3ddb79c0VDeD-Oft5eNfMneTU3D1dQ xen-2.4.16/include/xeno/skbuff.h
 3ddb79c14dXIhP7C2ahnoD08K90G_w xen-2.4.16/include/xeno/slab.h
index 6ee5c93c0306198dc45dbbe3fae9554924c814f6..9eecfef2f5b5050567fc25bc3bc4104d618ae7ef 100644 (file)
@@ -12,8 +12,6 @@
  */
 
 #define __KERNEL_SYSCALLS__
-#include <stdarg.h>
-
 #include <xeno/config.h>
 #include <xeno/lib.h>
 #include <xeno/errno.h>
index 4b46be791ac8aaa1440ada9a9bc5ba1166a09b92..54d48823edb06dc29cf3f4d3c3a555b2ae94934d 100644 (file)
@@ -3,8 +3,10 @@ include $(BASEDIR)/Rules.mk
 
 default: $(OBJS)
        $(MAKE) -C tulip
-       $(LD) -r -o driver.o $(OBJS) tulip/tulip.o 
+       $(MAKE) -C e1000
+       $(LD) -r -o driver.o $(OBJS) tulip/tulip.o e1000/e1000.o
 
 clean:
        $(MAKE) -C tulip clean
+       $(MAKE) -C e1000 clean
        rm -f *.o *~ core
diff --git a/xen-2.4.16/drivers/net/e1000/LICENSE b/xen-2.4.16/drivers/net/e1000/LICENSE
new file mode 100644 (file)
index 0000000..5f297e5
--- /dev/null
@@ -0,0 +1,339 @@
+
+"This software program is licensed subject to the GNU General Public License 
+(GPL). Version 2, June 1991, available at 
+<http://www.fsf.org/copyleft/gpl.html>"
+
+GNU General Public License 
+
+Version 2, June 1991
+
+Copyright (C) 1989, 1991 Free Software Foundation, Inc.  
+59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
+
+Everyone is permitted to copy and distribute verbatim copies of this license
+document, but changing it is not allowed.
+
+Preamble
+
+The licenses for most software are designed to take away your freedom to 
+share and change it. By contrast, the GNU General Public License is intended
+to guarantee your freedom to share and change free software--to make sure 
+the software is free for all its users. This General Public License applies 
+to most of the Free Software Foundation's software and to any other program 
+whose authors commit to using it. (Some other Free Software Foundation 
+software is covered by the GNU Library General Public License instead.) You 
+can apply it to your programs, too.
+
+When we speak of free software, we are referring to freedom, not price. Our
+General Public Licenses are designed to make sure that you have the freedom 
+to distribute copies of free software (and charge for this service if you 
+wish), that you receive source code or can get it if you want it, that you 
+can change the software or use pieces of it in new free programs; and that 
+you know you can do these things.
+
+To protect your rights, we need to make restrictions that forbid anyone to 
+deny you these rights or to ask you to surrender the rights. These 
+restrictions translate to certain responsibilities for you if you distribute
+copies of the software, or if you modify it.
+
+For example, if you distribute copies of such a program, whether gratis or 
+for a fee, you must give the recipients all the rights that you have. You 
+must make sure that they, too, receive or can get the source code. And you 
+must show them these terms so they know their rights.
+We protect your rights with two steps: (1) copyright the software, and (2) 
+offer you this license which gives you legal permission to copy, distribute 
+and/or modify the software. 
+
+Also, for each author's protection and ours, we want to make certain that 
+everyone understands that there is no warranty for this free software. If 
+the software is modified by someone else and passed on, we want its 
+recipients to know that what they have is not the original, so that any 
+problems introduced by others will not reflect on the original authors' 
+reputations. 
+
+Finally, any free program is threatened constantly by software patents. We 
+wish to avoid the danger that redistributors of a free program will 
+individually obtain patent licenses, in effect making the program 
+proprietary. To prevent this, we have made it clear that any patent must be 
+licensed for everyone's free use or not licensed at all. 
+
+The precise terms and conditions for copying, distribution and modification 
+follow. 
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+0. This License applies to any program or other work which contains a notice
+   placed by the copyright holder saying it may be distributed under the 
+   terms of this General Public License. The "Program", below, refers to any
+   such program or work, and a "work based on the Program" means either the 
+   Program or any derivative work under copyright law: that is to say, a 
+   work containing the Program or a portion of it, either verbatim or with 
+   modifications and/or translated into another language. (Hereinafter, 
+   translation is included without limitation in the term "modification".) 
+   Each licensee is addressed as "you". 
+
+   Activities other than copying, distribution and modification are not 
+   covered by this License; they are outside its scope. The act of running 
+   the Program is not restricted, and the output from the Program is covered 
+   only if its contents constitute a work based on the Program (independent 
+   of having been made by running the Program). Whether that is true depends
+   on what the Program does. 
+
+1. You may copy and distribute verbatim copies of the Program's source code 
+   as you receive it, in any medium, provided that you conspicuously and 
+   appropriately publish on each copy an appropriate copyright notice and 
+   disclaimer of warranty; keep intact all the notices that refer to this 
+   License and to the absence of any warranty; and give any other recipients 
+   of the Program a copy of this License along with the Program. 
+
+   You may charge a fee for the physical act of transferring a copy, and you 
+   may at your option offer warranty protection in exchange for a fee. 
+
+2. You may modify your copy or copies of the Program or any portion of it, 
+   thus forming a work based on the Program, and copy and distribute such 
+   modifications or work under the terms of Section 1 above, provided that 
+   you also meet all of these conditions: 
+
+   * a) You must cause the modified files to carry prominent notices stating 
+        that you changed the files and the date of any change. 
+
+   * b) You must cause any work that you distribute or publish, that in 
+        whole or in part contains or is derived from the Program or any part 
+        thereof, to be licensed as a whole at no charge to all third parties
+        under the terms of this License. 
+
+   * c) If the modified program normally reads commands interactively when 
+        run, you must cause it, when started running for such interactive 
+        use in the most ordinary way, to print or display an announcement 
+        including an appropriate copyright notice and a notice that there is
+        no warranty (or else, saying that you provide a warranty) and that 
+        users may redistribute the program under these conditions, and 
+        telling the user how to view a copy of this License. (Exception: if 
+        the Program itself is interactive but does not normally print such 
+        an announcement, your work based on the Program is not required to 
+        print an announcement.) 
+
+   These requirements apply to the modified work as a whole. If identifiable 
+   sections of that work are not derived from the Program, and can be 
+   reasonably considered independent and separate works in themselves, then 
+   this License, and its terms, do not apply to those sections when you 
+   distribute them as separate works. But when you distribute the same 
+   sections as part of a whole which is a work based on the Program, the 
+   distribution of the whole must be on the terms of this License, whose 
+   permissions for other licensees extend to the entire whole, and thus to 
+   each and every part regardless of who wrote it. 
+
+   Thus, it is not the intent of this section to claim rights or contest 
+   your rights to work written entirely by you; rather, the intent is to 
+   exercise the right to control the distribution of derivative or 
+   collective works based on the Program. 
+
+   In addition, mere aggregation of another work not based on the Program 
+   with the Program (or with a work based on the Program) on a volume of a 
+   storage or distribution medium does not bring the other work under the 
+   scope of this License. 
+
+3. You may copy and distribute the Program (or a work based on it, under 
+   Section 2) in object code or executable form under the terms of Sections 
+   1 and 2 above provided that you also do one of the following: 
+
+   * a) Accompany it with the complete corresponding machine-readable source 
+        code, which must be distributed under the terms of Sections 1 and 2 
+        above on a medium customarily used for software interchange; or, 
+
+   * b) Accompany it with a written offer, valid for at least three years, 
+        to give any third party, for a charge no more than your cost of 
+        physically performing source distribution, a complete machine-
+        readable copy of the corresponding source code, to be distributed 
+        under the terms of Sections 1 and 2 above on a medium customarily 
+        used for software interchange; or, 
+
+   * c) Accompany it with the information you received as to the offer to 
+        distribute corresponding source code. (This alternative is allowed 
+        only for noncommercial distribution and only if you received the 
+        program in object code or executable form with such an offer, in 
+        accord with Subsection b above.) 
+
+   The source code for a work means the preferred form of the work for 
+   making modifications to it. For an executable work, complete source code 
+   means all the source code for all modules it contains, plus any 
+   associated interface definition files, plus the scripts used to control 
+   compilation and installation of the executable. However, as a special 
+   exception, the source code distributed need not include anything that is 
+   normally distributed (in either source or binary form) with the major 
+   components (compiler, kernel, and so on) of the operating system on which
+   the executable runs, unless that component itself accompanies the 
+   executable. 
+
+   If distribution of executable or object code is made by offering access 
+   to copy from a designated place, then offering equivalent access to copy 
+   the source code from the same place counts as distribution of the source 
+   code, even though third parties are not compelled to copy the source 
+   along with the object code. 
+
+4. You may not copy, modify, sublicense, or distribute the Program except as
+   expressly provided under this License. Any attempt otherwise to copy, 
+   modify, sublicense or distribute the Program is void, and will 
+   automatically terminate your rights under this License. However, parties 
+   who have received copies, or rights, from you under this License will not
+   have their licenses terminated so long as such parties remain in full 
+   compliance. 
+
+5. You are not required to accept this License, since you have not signed 
+   it. However, nothing else grants you permission to modify or distribute 
+   the Program or its derivative works. These actions are prohibited by law 
+   if you do not accept this License. Therefore, by modifying or 
+   distributing the Program (or any work based on the Program), you 
+   indicate your acceptance of this License to do so, and all its terms and
+   conditions for copying, distributing or modifying the Program or works 
+   based on it. 
+
+6. Each time you redistribute the Program (or any work based on the 
+   Program), the recipient automatically receives a license from the 
+   original licensor to copy, distribute or modify the Program subject to 
+   these terms and conditions. You may not impose any further restrictions 
+   on the recipients' exercise of the rights granted herein. You are not 
+   responsible for enforcing compliance by third parties to this License. 
+
+7. If, as a consequence of a court judgment or allegation of patent 
+   infringement or for any other reason (not limited to patent issues), 
+   conditions are imposed on you (whether by court order, agreement or 
+   otherwise) that contradict the conditions of this License, they do not 
+   excuse you from the conditions of this License. If you cannot distribute 
+   so as to satisfy simultaneously your obligations under this License and 
+   any other pertinent obligations, then as a consequence you may not 
+   distribute the Program at all. For example, if a patent license would 
+   not permit royalty-free redistribution of the Program by all those who 
+   receive copies directly or indirectly through you, then the only way you 
+   could satisfy both it and this License would be to refrain entirely from 
+   distribution of the Program. 
+
+   If any portion of this section is held invalid or unenforceable under any
+   particular circumstance, the balance of the section is intended to apply
+   and the section as a whole is intended to apply in other circumstances. 
+
+   It is not the purpose of this section to induce you to infringe any 
+   patents or other property right claims or to contest validity of any 
+   such claims; this section has the sole purpose of protecting the 
+   integrity of the free software distribution system, which is implemented 
+   by public license practices. Many people have made generous contributions
+   to the wide range of software distributed through that system in 
+   reliance on consistent application of that system; it is up to the 
+   author/donor to decide if he or she is willing to distribute software 
+   through any other system and a licensee cannot impose that choice. 
+
+   This section is intended to make thoroughly clear what is believed to be 
+   a consequence of the rest of this License. 
+
+8. If the distribution and/or use of the Program is restricted in certain 
+   countries either by patents or by copyrighted interfaces, the original 
+   copyright holder who places the Program under this License may add an 
+   explicit geographical distribution limitation excluding those countries, 
+   so that distribution is permitted only in or among countries not thus 
+   excluded. In such case, this License incorporates the limitation as if 
+   written in the body of this License. 
+
+9. The Free Software Foundation may publish revised and/or new versions of 
+   the General Public License from time to time. Such new versions will be 
+   similar in spirit to the present version, but may differ in detail to 
+   address new problems or concerns. 
+
+   Each version is given a distinguishing version number. If the Program 
+   specifies a version number of this License which applies to it and "any 
+   later version", you have the option of following the terms and 
+   conditions either of that version or of any later version published by 
+   the Free Software Foundation. If the Program does not specify a version 
+   number of this License, you may choose any version ever published by the 
+   Free Software Foundation. 
+
+10. If you wish to incorporate parts of the Program into other free programs
+    whose distribution conditions are different, write to the author to ask 
+    for permission. For software which is copyrighted by the Free Software 
+    Foundation, write to the Free Software Foundation; we sometimes make 
+    exceptions for this. Our decision will be guided by the two goals of 
+    preserving the free status of all derivatives of our free software and 
+    of promoting the sharing and reuse of software generally. 
+
+   NO WARRANTY
+
+11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 
+    FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 
+    OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 
+    PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER 
+    EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
+    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE 
+    ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH 
+    YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL 
+    NECESSARY SERVICING, REPAIR OR CORRECTION. 
+
+12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 
+    WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 
+    REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR 
+    DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL 
+    DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM 
+    (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED 
+    INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF 
+    THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR 
+    OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 
+
+END OF TERMS AND CONDITIONS
+
+How to Apply These Terms to Your New Programs
+
+If you develop a new program, and you want it to be of the greatest 
+possible use to the public, the best way to achieve this is to make it free 
+software which everyone can redistribute and change under these terms. 
+
+To do so, attach the following notices to the program. It is safest to 
+attach them to the start of each source file to most effectively convey the
+exclusion of warranty; and each file should have at least the "copyright" 
+line and a pointer to where the full notice is found. 
+
+one line to give the program's name and an idea of what it does.
+Copyright (C) yyyy  name of author
+
+This program is free software; you can redistribute it and/or modify it 
+under the terms of the GNU General Public License as published by the Free 
+Software Foundation; either version 2 of the License, or (at your option) 
+any later version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT 
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 
+Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+
+Also add information on how to contact you by electronic and paper mail. 
+
+If the program is interactive, make it output a short notice like this when 
+it starts in an interactive mode: 
+
+Gnomovision version 69, Copyright (C) year name of author Gnomovision comes 
+with ABSOLUTELY NO WARRANTY; for details type 'show w'.  This is free 
+software, and you are welcome to redistribute it under certain conditions; 
+type 'show c' for details.
+
+The hypothetical commands 'show w' and 'show c' should show the appropriate 
+parts of the General Public License. Of course, the commands you use may be 
+called something other than 'show w' and 'show c'; they could even be 
+mouse-clicks or menu items--whatever suits your program. 
+
+You should also get your employer (if you work as a programmer) or your 
+school, if any, to sign a "copyright disclaimer" for the program, if 
+necessary. Here is a sample; alter the names: 
+
+Yoyodyne, Inc., hereby disclaims all copyright interest in the program 
+'Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+signature of Ty Coon, 1 April 1989
+Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into 
+proprietary programs. If your program is a subroutine library, you may 
+consider it more useful to permit linking proprietary applications with the 
+library. If this is what you want to do, use the GNU Library General Public 
+License instead of this License.
diff --git a/xen-2.4.16/drivers/net/e1000/Makefile b/xen-2.4.16/drivers/net/e1000/Makefile
new file mode 100644 (file)
index 0000000..f262fcf
--- /dev/null
@@ -0,0 +1,39 @@
+################################################################################
+#
+# 
+# Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+# 
+# This program is free software; you can redistribute it and/or modify it 
+# under the terms of the GNU General Public License as published by the Free 
+# Software Foundation; either version 2 of the License, or (at your option) 
+# any later version.
+# 
+# This program is distributed in the hope that it will be useful, but WITHOUT 
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+# more details.
+# 
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 59 
+# Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+# 
+# The full GNU General Public License is included in this distribution in the
+# file called LICENSE.
+# 
+# Contact Information:
+# Linux NICS <linux.nics@intel.com>
+# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+#
+################################################################################
+
+#
+# Makefile for the Intel(R) PRO/1000 ethernet driver
+#
+
+include $(BASEDIR)/Rules.mk
+
+default: $(OBJS)
+       $(LD) -r -o e1000.o $(OBJS)
+
+clean:
+       rm -f *.o *~ core
diff --git a/xen-2.4.16/drivers/net/e1000/e1000.h b/xen-2.4.16/drivers/net/e1000/e1000.h
new file mode 100644 (file)
index 0000000..ec7c27a
--- /dev/null
@@ -0,0 +1,209 @@
+/*******************************************************************************
+
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  This program is free software; you can redistribute it and/or modify it 
+  under the terms of the GNU General Public License as published by the Free 
+  Software Foundation; either version 2 of the License, or (at your option) 
+  any later version.
+  
+  This program is distributed in the hope that it will be useful, but WITHOUT 
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+  more details.
+  
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59 
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+
+/* Linux PRO/1000 Ethernet Driver main header file */
+
+#ifndef _E1000_H_
+#define _E1000_H_
+
+//#include <linux/stddef.h>
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+//#include <linux/string.h>
+//#include <linux/pagemap.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+//#include <linux/capability.h>
+#include <linux/in.h>
+//#include <linux/ip.h>
+//#include <linux/tcp.h>
+//#include <linux/udp.h>
+//#include <net/pkt_sched.h>
+#include <linux/list.h>
+#include <linux/reboot.h>
+#include <linux/tqueue.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+
+#define BAR_0          0
+#define BAR_1          1
+#define BAR_5          5
+#define PCI_DMA_64BIT  0xffffffffffffffffULL
+#define PCI_DMA_32BIT  0x00000000ffffffffULL
+
+
+struct e1000_adapter;
+
+// XEN XXX
+#define DBG 1
+
+#include "e1000_hw.h"
+
+#if DBG
+#define E1000_DBG(args...) printk(KERN_DEBUG "e1000: " args)
+#else
+XXX
+#define E1000_DBG(args...)
+#endif
+
+#define E1000_ERR(args...) printk(KERN_ERR "e1000: " args)
+
+#define E1000_MAX_INTR 10
+
+/* Supported Rx Buffer Sizes */
+#define E1000_RXBUFFER_2048  2048
+#define E1000_RXBUFFER_4096  4096
+#define E1000_RXBUFFER_8192  8192
+#define E1000_RXBUFFER_16384 16384
+
+/* Flow Control High-Watermark: 43464 bytes */
+#define E1000_FC_HIGH_THRESH 0xA9C8
+
+/* Flow Control Low-Watermark: 43456 bytes */
+#define E1000_FC_LOW_THRESH 0xA9C0
+
+/* Flow Control Pause Time: 858 usec */
+#define E1000_FC_PAUSE_TIME 0x0680
+
+/* How many Tx Descriptors do we need to call netif_wake_queue ? */
+#define E1000_TX_QUEUE_WAKE    16
+/* How many Rx Buffers do we bundle into one write to the hardware ? */
+#define E1000_RX_BUFFER_WRITE  16
+
+#define E1000_JUMBO_PBA      0x00000028
+#define E1000_DEFAULT_PBA    0x00000030
+
+#define AUTO_ALL_MODES       0
+#define E1000_EEPROM_APME    4
+
+/* only works for sizes that are powers of 2 */
+#define E1000_ROUNDUP(i, size) ((i) = (((i) + (size) - 1) & ~((size) - 1)))
+
+/* wrapper around a pointer to a socket buffer,
+ * so a DMA handle can be stored along with the buffer */
+struct e1000_buffer {
+       struct sk_buff *skb;
+       uint64_t dma;
+       unsigned long length;
+       unsigned long time_stamp;
+};
+
+struct e1000_desc_ring {
+       /* pointer to the descriptor ring memory */
+       void *desc;
+       /* physical address of the descriptor ring */
+       dma_addr_t dma;
+       /* length of descriptor ring in bytes */
+       unsigned int size;
+       /* number of descriptors in the ring */
+       unsigned int count;
+       /* next descriptor to associate a buffer with */
+       unsigned int next_to_use;
+       /* next descriptor to check for DD status bit */
+       unsigned int next_to_clean;
+       /* array of buffer information structs */
+       struct e1000_buffer *buffer_info;
+};
+
+#define E1000_DESC_UNUSED(R) \
+((((R)->next_to_clean + (R)->count) - ((R)->next_to_use + 1)) % ((R)->count))
+
+#define E1000_GET_DESC(R, i, type)     (&(((struct type *)((R).desc))[i]))
+#define E1000_RX_DESC(R, i)            E1000_GET_DESC(R, i, e1000_rx_desc)
+#define E1000_TX_DESC(R, i)            E1000_GET_DESC(R, i, e1000_tx_desc)
+#define E1000_CONTEXT_DESC(R, i)       E1000_GET_DESC(R, i, e1000_context_desc)
+
+/* board specific private data structure */
+
+struct e1000_adapter {
+       struct timer_list watchdog_timer;
+       struct timer_list phy_info_timer;
+       struct vlan_group *vlgrp;
+       char *id_string;
+       uint32_t bd_number;
+       uint32_t rx_buffer_len;
+       uint32_t part_num;
+       uint32_t wol;
+       uint16_t link_speed;
+       uint16_t link_duplex;
+       spinlock_t stats_lock;
+       atomic_t irq_sem;
+       struct tq_struct tx_timeout_task;
+
+       struct timer_list blink_timer;
+       unsigned long led_status;
+
+       /* TX */
+       struct e1000_desc_ring tx_ring;
+       uint32_t txd_cmd;
+       uint32_t tx_int_delay;
+       uint32_t tx_abs_int_delay;
+       int max_data_per_txd;
+
+       /* RX */
+       struct e1000_desc_ring rx_ring;
+       uint64_t hw_csum_err;
+       uint64_t hw_csum_good;
+       uint32_t rx_int_delay;
+       uint32_t rx_abs_int_delay;
+       boolean_t rx_csum;
+
+       /* OS defined structs */
+       struct net_device *netdev;
+       struct pci_dev *pdev;
+       struct net_device_stats net_stats;
+
+       /* structs defined in e1000_hw.h */
+       struct e1000_hw hw;
+       struct e1000_hw_stats stats;
+       struct e1000_phy_info phy_info;
+       struct e1000_phy_stats phy_stats;
+
+
+
+       uint32_t pci_state[16];
+       char ifname[IFNAMSIZ];
+};
+#endif /* _E1000_H_ */
diff --git a/xen-2.4.16/drivers/net/e1000/e1000_ethtool.c b/xen-2.4.16/drivers/net/e1000/e1000_ethtool.c
new file mode 100644 (file)
index 0000000..d06ef79
--- /dev/null
@@ -0,0 +1,611 @@
+/*******************************************************************************
+
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  This program is free software; you can redistribute it and/or modify it 
+  under the terms of the GNU General Public License as published by the Free 
+  Software Foundation; either version 2 of the License, or (at your option) 
+  any later version.
+  
+  This program is distributed in the hope that it will be useful, but WITHOUT 
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+  more details.
+  
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59 
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/* ethtool support for e1000 */
+
+#include "e1000.h"
+
+#include <asm/uaccess.h>
+
+extern char e1000_driver_name[];
+extern char e1000_driver_version[];
+
+extern int e1000_up(struct e1000_adapter *adapter);
+extern void e1000_down(struct e1000_adapter *adapter);
+extern void e1000_reset(struct e1000_adapter *adapter);
+
+static char e1000_gstrings_stats[][ETH_GSTRING_LEN] = {
+       "rx_packets", "tx_packets", "rx_bytes", "tx_bytes", "rx_errors",
+       "tx_errors", "rx_dropped", "tx_dropped", "multicast", "collisions",
+       "rx_length_errors", "rx_over_errors", "rx_crc_errors",
+       "rx_frame_errors", "rx_fifo_errors", "rx_missed_errors",
+       "tx_aborted_errors", "tx_carrier_errors", "tx_fifo_errors",
+       "tx_heartbeat_errors", "tx_window_errors",
+};
+#define E1000_STATS_LEN        sizeof(e1000_gstrings_stats) / ETH_GSTRING_LEN
+
+static void
+e1000_ethtool_gset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd)
+{
+       struct e1000_hw *hw = &adapter->hw;
+
+       if(hw->media_type == e1000_media_type_copper) {
+
+               ecmd->supported = (SUPPORTED_10baseT_Half |
+                                  SUPPORTED_10baseT_Full |
+                                  SUPPORTED_100baseT_Half |
+                                  SUPPORTED_100baseT_Full |
+                                  SUPPORTED_1000baseT_Full|
+                                  SUPPORTED_Autoneg |
+                                  SUPPORTED_TP);
+
+               ecmd->advertising = ADVERTISED_TP;
+
+               if(hw->autoneg == 1) {
+                       ecmd->advertising |= ADVERTISED_Autoneg;
+
+                       /* the e1000 autoneg seems to match ethtool nicely */
+
+                       ecmd->advertising |= hw->autoneg_advertised;
+               }
+
+               ecmd->port = PORT_TP;
+               ecmd->phy_address = hw->phy_addr;
+
+               if(hw->mac_type == e1000_82543)
+                       ecmd->transceiver = XCVR_EXTERNAL;
+               else
+                       ecmd->transceiver = XCVR_INTERNAL;
+
+       } else {
+               ecmd->supported   = (SUPPORTED_1000baseT_Full |
+                                    SUPPORTED_FIBRE |
+                                    SUPPORTED_Autoneg);
+
+               ecmd->advertising = (SUPPORTED_1000baseT_Full |
+                                    SUPPORTED_FIBRE |
+                                    SUPPORTED_Autoneg);
+
+               ecmd->port = PORT_FIBRE;
+
+               if(hw->mac_type >= e1000_82545)
+                       ecmd->transceiver = XCVR_INTERNAL;
+               else
+                       ecmd->transceiver = XCVR_EXTERNAL;
+       }
+
+       if(netif_carrier_ok(adapter->netdev)) {
+
+               e1000_get_speed_and_duplex(hw, &adapter->link_speed,
+                                                  &adapter->link_duplex);
+               ecmd->speed = adapter->link_speed;
+
+               /* unfortunatly FULL_DUPLEX != DUPLEX_FULL
+                *          and HALF_DUPLEX != DUPLEX_HALF */
+
+               if(adapter->link_duplex == FULL_DUPLEX)
+                       ecmd->duplex = DUPLEX_FULL;
+               else
+                       ecmd->duplex = DUPLEX_HALF;
+       } else {
+               ecmd->speed = -1;
+               ecmd->duplex = -1;
+       }
+
+       ecmd->autoneg = (hw->autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE);
+}
+
+static int
+e1000_ethtool_sset(struct e1000_adapter *adapter, struct ethtool_cmd *ecmd)
+{
+       struct e1000_hw *hw = &adapter->hw;
+
+       if(ecmd->autoneg == AUTONEG_ENABLE) {
+               hw->autoneg = 1;
+               hw->autoneg_advertised = 0x002F;
+               ecmd->advertising = 0x002F;
+       } else {
+               hw->autoneg = 0;
+               switch(ecmd->speed + ecmd->duplex) {
+               case SPEED_10 + DUPLEX_HALF:
+                       hw->forced_speed_duplex = e1000_10_half;
+                       break;
+               case SPEED_10 + DUPLEX_FULL:
+                       hw->forced_speed_duplex = e1000_10_full;
+                       break;
+               case SPEED_100 + DUPLEX_HALF:
+                       hw->forced_speed_duplex = e1000_100_half;
+                       break;
+               case SPEED_100 + DUPLEX_FULL:
+                       hw->forced_speed_duplex = e1000_100_full;
+                       break;
+               case SPEED_1000 + DUPLEX_FULL:
+                       hw->autoneg = 1;
+                       hw->autoneg_advertised = ADVERTISE_1000_FULL;
+                       break;
+               case SPEED_1000 + DUPLEX_HALF: /* not supported */
+               default:
+                       return -EINVAL;
+               }
+       }
+
+       /* reset the link */
+
+       if(netif_running(adapter->netdev)) {
+               e1000_down(adapter);
+               e1000_up(adapter);
+       } else
+               e1000_reset(adapter);
+
+       return 0;
+}
+
+static inline int
+e1000_eeprom_size(struct e1000_hw *hw)
+{
+       if((hw->mac_type > e1000_82544) &&
+          (E1000_READ_REG(hw, EECD) & E1000_EECD_SIZE))
+               return 512;
+       else
+               return 128;
+}
+
+static void
+e1000_ethtool_gdrvinfo(struct e1000_adapter *adapter,
+                       struct ethtool_drvinfo *drvinfo)
+{
+       strncpy(drvinfo->driver,  e1000_driver_name, 32);
+       strncpy(drvinfo->version, e1000_driver_version, 32);
+       strncpy(drvinfo->fw_version, "N/A", 32);
+       strncpy(drvinfo->bus_info, adapter->pdev->slot_name, 32);
+       drvinfo->n_stats = E1000_STATS_LEN;
+#define E1000_REGS_LEN 32
+       drvinfo->regdump_len  = E1000_REGS_LEN * sizeof(uint32_t);
+       drvinfo->eedump_len  = e1000_eeprom_size(&adapter->hw);
+}
+
+static void
+e1000_ethtool_gregs(struct e1000_adapter *adapter,
+                    struct ethtool_regs *regs, uint32_t *regs_buff)
+{
+       struct e1000_hw *hw = &adapter->hw;
+
+       regs->version = (1 << 24) | (hw->revision_id << 16) | hw->device_id;
+
+       regs_buff[0]  = E1000_READ_REG(hw, CTRL);
+       regs_buff[1]  = E1000_READ_REG(hw, STATUS);
+
+       regs_buff[2]  = E1000_READ_REG(hw, RCTL);
+       regs_buff[3]  = E1000_READ_REG(hw, RDLEN);
+       regs_buff[4]  = E1000_READ_REG(hw, RDH);
+       regs_buff[5]  = E1000_READ_REG(hw, RDT);
+       regs_buff[6]  = E1000_READ_REG(hw, RDTR);
+
+       regs_buff[7]  = E1000_READ_REG(hw, TCTL);
+       regs_buff[8]  = E1000_READ_REG(hw, TDLEN);
+       regs_buff[9]  = E1000_READ_REG(hw, TDH);
+       regs_buff[10] = E1000_READ_REG(hw, TDT);
+       regs_buff[11] = E1000_READ_REG(hw, TIDV);
+
+       return;
+}
+
+static int
+e1000_ethtool_geeprom(struct e1000_adapter *adapter,
+                      struct ethtool_eeprom *eeprom, uint16_t *eeprom_buff)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       int max_len, first_word, last_word;
+       int ret_val = 0;
+       int i;
+
+       if(eeprom->len == 0) {
+               ret_val = -EINVAL;
+               goto geeprom_error;
+       }
+
+       eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+       max_len = e1000_eeprom_size(hw);
+
+       if(eeprom->offset > eeprom->offset + eeprom->len) {
+               ret_val = -EINVAL;
+               goto geeprom_error;
+       }
+
+       if((eeprom->offset + eeprom->len) > max_len)
+               eeprom->len = (max_len - eeprom->offset);
+
+       first_word = eeprom->offset >> 1;
+       last_word = (eeprom->offset + eeprom->len - 1) >> 1;
+
+       for(i = 0; i <= (last_word - first_word); i++)
+               e1000_read_eeprom(hw, first_word + i, &eeprom_buff[i]);
+
+geeprom_error:
+       return ret_val;
+}
+
+static int
+e1000_ethtool_seeprom(struct e1000_adapter *adapter,
+                      struct ethtool_eeprom *eeprom, void *user_data)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       uint16_t *eeprom_buff;
+       int max_len, first_word, last_word;
+       void *ptr;
+       int i;
+
+       if(eeprom->len == 0)
+               return -EOPNOTSUPP;
+
+       if(eeprom->magic != (hw->vendor_id | (hw->device_id << 16)))
+               return -EFAULT;
+
+       max_len = e1000_eeprom_size(hw);
+
+       if((eeprom->offset + eeprom->len) > max_len)
+               eeprom->len = (max_len - eeprom->offset);
+
+       first_word = eeprom->offset >> 1;
+       last_word = (eeprom->offset + eeprom->len - 1) >> 1;
+       eeprom_buff = kmalloc(max_len, GFP_KERNEL);
+       if(eeprom_buff == NULL)
+               return -ENOMEM;
+
+       ptr = (void *)eeprom_buff;
+
+       if(eeprom->offset & 1) {
+               /* need read/modify/write of first changed EEPROM word */
+               /* only the second byte of the word is being modified */
+               e1000_read_eeprom(hw, first_word, &eeprom_buff[0]);
+               ptr++;
+       }
+       if((eeprom->offset + eeprom->len) & 1) {
+               /* need read/modify/write of last changed EEPROM word */
+               /* only the first byte of the word is being modified */
+               e1000_read_eeprom(hw, last_word,
+                                 &eeprom_buff[last_word - first_word]);
+       }
+       if(copy_from_user(ptr, user_data, eeprom->len)) {
+               kfree(eeprom_buff);
+               return -EFAULT;
+       }
+
+       for(i = 0; i <= (last_word - first_word); i++)
+               e1000_write_eeprom(hw, first_word + i, eeprom_buff[i]);
+
+       /* Update the checksum over the first part of the EEPROM if needed */
+       if(first_word <= EEPROM_CHECKSUM_REG)
+               e1000_update_eeprom_checksum(hw);
+
+       kfree(eeprom_buff);
+
+       return 0;
+}
+
+static void
+e1000_ethtool_gwol(struct e1000_adapter *adapter, struct ethtool_wolinfo *wol)
+{
+       struct e1000_hw *hw = &adapter->hw;
+
+       switch(adapter->hw.device_id) {
+       case E1000_DEV_ID_82542:
+       case E1000_DEV_ID_82543GC_FIBER:
+       case E1000_DEV_ID_82543GC_COPPER:
+       case E1000_DEV_ID_82544EI_FIBER:
+               wol->supported = 0;
+               wol->wolopts   = 0;
+               return;
+
+       case E1000_DEV_ID_82546EB_FIBER:
+               /* Wake events only supported on port A for dual fiber */
+               if(E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1) {
+                       wol->supported = 0;
+                       wol->wolopts   = 0;
+                       return;
+               }
+               /* Fall Through */
+
+       default:
+               wol->supported = WAKE_UCAST | WAKE_MCAST
+                                | WAKE_BCAST | WAKE_MAGIC;
+
+               wol->wolopts = 0;
+               if(adapter->wol & E1000_WUFC_EX)
+                       wol->wolopts |= WAKE_UCAST;
+               if(adapter->wol & E1000_WUFC_MC)
+                       wol->wolopts |= WAKE_MCAST;
+               if(adapter->wol & E1000_WUFC_BC)
+                       wol->wolopts |= WAKE_BCAST;
+               if(adapter->wol & E1000_WUFC_MAG)
+                       wol->wolopts |= WAKE_MAGIC;
+               return;
+       }
+}
+
+static int
+e1000_ethtool_swol(struct e1000_adapter *adapter, struct ethtool_wolinfo *wol)
+{
+       struct e1000_hw *hw = &adapter->hw;
+
+       switch(adapter->hw.device_id) {
+       case E1000_DEV_ID_82542:
+       case E1000_DEV_ID_82543GC_FIBER:
+       case E1000_DEV_ID_82543GC_COPPER:
+       case E1000_DEV_ID_82544EI_FIBER:
+               return wol->wolopts ? -EOPNOTSUPP : 0;
+
+       case E1000_DEV_ID_82546EB_FIBER:
+               /* Wake events only supported on port A for dual fiber */
+               if(E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)
+                       return wol->wolopts ? -EOPNOTSUPP : 0;
+               /* Fall Through */
+
+       default:
+               if(wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE | WAKE_PHY))
+                       return -EOPNOTSUPP;
+
+               adapter->wol = 0;
+
+               if(wol->wolopts & WAKE_UCAST)
+                       adapter->wol |= E1000_WUFC_EX;
+               if(wol->wolopts & WAKE_MCAST)
+                       adapter->wol |= E1000_WUFC_MC;
+               if(wol->wolopts & WAKE_BCAST)
+                       adapter->wol |= E1000_WUFC_BC;
+               if(wol->wolopts & WAKE_MAGIC)
+                       adapter->wol |= E1000_WUFC_MAG;
+       }
+
+       return 0;
+}
+
+
+/* toggle LED 4 times per second = 2 "blinks" per second */
+#define E1000_ID_INTERVAL      (HZ/4)
+
+/* bit defines for adapter->led_status */
+#define E1000_LED_ON           0
+
+static void
+e1000_led_blink_callback(unsigned long data)
+{
+       struct e1000_adapter *adapter = (struct e1000_adapter *) data;
+
+       if(test_and_change_bit(E1000_LED_ON, &adapter->led_status))
+               e1000_led_off(&adapter->hw);
+       else
+               e1000_led_on(&adapter->hw);
+
+       mod_timer(&adapter->blink_timer, jiffies + E1000_ID_INTERVAL);
+}
+
+static int
+e1000_ethtool_led_blink(struct e1000_adapter *adapter, struct ethtool_value *id)
+{
+       if(!adapter->blink_timer.function) {
+               init_timer(&adapter->blink_timer);
+               adapter->blink_timer.function = e1000_led_blink_callback;
+               adapter->blink_timer.data = (unsigned long) adapter;
+       }
+
+       e1000_setup_led(&adapter->hw);
+       mod_timer(&adapter->blink_timer, jiffies);
+
+       set_current_state(TASK_INTERRUPTIBLE);
+       if(id->data)
+               schedule_timeout(id->data * HZ);
+       else
+               schedule_timeout(MAX_SCHEDULE_TIMEOUT);
+
+       del_timer_sync(&adapter->blink_timer);
+       e1000_led_off(&adapter->hw);
+       clear_bit(E1000_LED_ON, &adapter->led_status);
+       e1000_cleanup_led(&adapter->hw);
+
+       return 0;
+}
+
+int
+e1000_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr)
+{
+       struct e1000_adapter *adapter = netdev->priv;
+       void *addr = ifr->ifr_data;
+       uint32_t cmd;
+
+       if(get_user(cmd, (uint32_t *) addr))
+               return -EFAULT;
+
+       switch(cmd) {
+       case ETHTOOL_GSET: {
+               struct ethtool_cmd ecmd = {ETHTOOL_GSET};
+               e1000_ethtool_gset(adapter, &ecmd);
+               if(copy_to_user(addr, &ecmd, sizeof(ecmd)))
+                       return -EFAULT;
+               return 0;
+       }
+       case ETHTOOL_SSET: {
+               struct ethtool_cmd ecmd;
+               if(!capable(CAP_NET_ADMIN))
+                       return -EPERM;
+               if(copy_from_user(&ecmd, addr, sizeof(ecmd)))
+                       return -EFAULT;
+               return e1000_ethtool_sset(adapter, &ecmd);
+       }
+       case ETHTOOL_GDRVINFO: {
+               struct ethtool_drvinfo drvinfo = {ETHTOOL_GDRVINFO};
+               e1000_ethtool_gdrvinfo(adapter, &drvinfo);
+               if(copy_to_user(addr, &drvinfo, sizeof(drvinfo)))
+                       return -EFAULT;
+               return 0;
+       }
+       case ETHTOOL_GSTRINGS: {
+               struct ethtool_gstrings gstrings = { ETHTOOL_GSTRINGS };
+               char *strings = NULL;
+
+               if(copy_from_user(&gstrings, addr, sizeof(gstrings)))
+                       return -EFAULT;
+               switch(gstrings.string_set) {
+               case ETH_SS_STATS:
+                       gstrings.len = E1000_STATS_LEN;
+                       strings = *e1000_gstrings_stats;
+                       break;
+               default:
+                       return -EOPNOTSUPP;
+               }
+               if(copy_to_user(addr, &gstrings, sizeof(gstrings)))
+                       return -EFAULT;
+               addr += offsetof(struct ethtool_gstrings, data);
+               if(copy_to_user(addr, strings,
+                  gstrings.len * ETH_GSTRING_LEN))
+                       return -EFAULT;
+               return 0;
+       }
+       case ETHTOOL_GREGS: {
+               struct ethtool_regs regs = {ETHTOOL_GREGS};
+               uint32_t regs_buff[E1000_REGS_LEN];
+
+               if(copy_from_user(&regs, addr, sizeof(regs)))
+                       return -EFAULT;
+               e1000_ethtool_gregs(adapter, &regs, regs_buff);
+               if(copy_to_user(addr, &regs, sizeof(regs)))
+                       return -EFAULT;
+
+               addr += offsetof(struct ethtool_regs, data);
+               if(copy_to_user(addr, regs_buff, regs.len))
+                       return -EFAULT;
+
+               return 0;
+       }
+       case ETHTOOL_NWAY_RST: {
+               if(!capable(CAP_NET_ADMIN))
+                       return -EPERM;
+               if(netif_running(netdev)) {
+                       e1000_down(adapter);
+                       e1000_up(adapter);
+               }
+               return 0;
+       }
+       case ETHTOOL_PHYS_ID: {
+               struct ethtool_value id;
+               if(copy_from_user(&id, addr, sizeof(id)))
+                       return -EFAULT;
+               return e1000_ethtool_led_blink(adapter, &id);
+       }
+       case ETHTOOL_GLINK: {
+               struct ethtool_value link = {ETHTOOL_GLINK};
+               link.data = netif_carrier_ok(netdev);
+               if(copy_to_user(addr, &link, sizeof(link)))
+                       return -EFAULT;
+               return 0;
+       }
+       case ETHTOOL_GWOL: {
+               struct ethtool_wolinfo wol = {ETHTOOL_GWOL};
+               e1000_ethtool_gwol(adapter, &wol);
+               if(copy_to_user(addr, &wol, sizeof(wol)) != 0)
+                       return -EFAULT;
+               return 0;
+       }
+       case ETHTOOL_SWOL: {
+               struct ethtool_wolinfo wol;
+               if(!capable(CAP_NET_ADMIN))
+                       return -EPERM;
+               if(copy_from_user(&wol, addr, sizeof(wol)) != 0)
+                       return -EFAULT;
+               return e1000_ethtool_swol(adapter, &wol);
+       }
+       case ETHTOOL_GEEPROM: {
+               struct ethtool_eeprom eeprom = {ETHTOOL_GEEPROM};
+               uint16_t *eeprom_buff;
+               void *ptr;
+               int max_len, err = 0;
+
+               max_len = e1000_eeprom_size(&adapter->hw);
+
+               eeprom_buff = kmalloc(max_len, GFP_KERNEL);
+
+               if(eeprom_buff == NULL)
+                       return -ENOMEM;
+
+               if(copy_from_user(&eeprom, addr, sizeof(eeprom))) {
+                       err = -EFAULT;
+                       goto err_geeprom_ioctl;
+               }
+
+               if((err = e1000_ethtool_geeprom(adapter, &eeprom,
+                                               eeprom_buff)))
+                       goto err_geeprom_ioctl;
+
+               if(copy_to_user(addr, &eeprom, sizeof(eeprom))) {
+                       err = -EFAULT;
+                       goto err_geeprom_ioctl;
+               }
+
+               addr += offsetof(struct ethtool_eeprom, data);
+               ptr = ((void *)eeprom_buff) + (eeprom.offset & 1);
+
+               if(copy_to_user(addr, ptr, eeprom.len))
+                       err = -EFAULT;
+
+err_geeprom_ioctl:
+               kfree(eeprom_buff);
+               return err;
+       }
+       case ETHTOOL_SEEPROM: {
+               struct ethtool_eeprom eeprom;
+
+               if(!capable(CAP_NET_ADMIN))
+                       return -EPERM;
+
+               if(copy_from_user(&eeprom, addr, sizeof(eeprom)))
+                       return -EFAULT;
+
+               addr += offsetof(struct ethtool_eeprom, data);
+               return e1000_ethtool_seeprom(adapter, &eeprom, addr);
+       }
+       case ETHTOOL_GSTATS: {
+               struct {
+                       struct ethtool_stats cmd;
+                       uint64_t data[E1000_STATS_LEN];
+               } stats = { {ETHTOOL_GSTATS, E1000_STATS_LEN} };
+               int i;
+
+               for(i = 0; i < E1000_STATS_LEN; i++)
+                       stats.data[i] =
+                               ((unsigned long *)&adapter->net_stats)[i];
+               if(copy_to_user(addr, &stats, sizeof(stats)))
+                       return -EFAULT;
+               return 0;
+       }
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+
diff --git a/xen-2.4.16/drivers/net/e1000/e1000_hw.c b/xen-2.4.16/drivers/net/e1000/e1000_hw.c
new file mode 100644 (file)
index 0000000..9105375
--- /dev/null
@@ -0,0 +1,3610 @@
+/*******************************************************************************
+
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  This program is free software; you can redistribute it and/or modify it 
+  under the terms of the GNU General Public License as published by the Free 
+  Software Foundation; either version 2 of the License, or (at your option) 
+  any later version.
+  
+  This program is distributed in the hope that it will be useful, but WITHOUT 
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+  more details.
+  
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59 
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/* e1000_hw.c
+ * Shared functions for accessing and configuring the MAC
+ */
+
+#include "e1000_hw.h"
+
+static int32_t e1000_setup_fiber_link(struct e1000_hw *hw);
+static int32_t e1000_setup_copper_link(struct e1000_hw *hw);
+static int32_t e1000_phy_force_speed_duplex(struct e1000_hw *hw);
+static int32_t e1000_config_mac_to_phy(struct e1000_hw *hw);
+static int32_t e1000_force_mac_fc(struct e1000_hw *hw);
+static void e1000_raise_mdi_clk(struct e1000_hw *hw, uint32_t *ctrl);
+static void e1000_lower_mdi_clk(struct e1000_hw *hw, uint32_t *ctrl);
+static void e1000_shift_out_mdi_bits(struct e1000_hw *hw, uint32_t data, uint16_t count);
+static uint16_t e1000_shift_in_mdi_bits(struct e1000_hw *hw);
+static int32_t e1000_phy_reset_dsp(struct e1000_hw *hw);
+static void e1000_raise_ee_clk(struct e1000_hw *hw, uint32_t *eecd);
+static void e1000_lower_ee_clk(struct e1000_hw *hw, uint32_t *eecd);
+static void e1000_shift_out_ee_bits(struct e1000_hw *hw, uint16_t data, uint16_t count);
+static uint16_t e1000_shift_in_ee_bits(struct e1000_hw *hw);
+static void e1000_setup_eeprom(struct e1000_hw *hw);
+static void e1000_clock_eeprom(struct e1000_hw *hw);
+static void e1000_cleanup_eeprom(struct e1000_hw *hw);
+static void e1000_standby_eeprom(struct e1000_hw *hw);
+static int32_t e1000_id_led_init(struct e1000_hw * hw);
+
+/******************************************************************************
+ * Set the mac type member in the hw struct.
+ * 
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+e1000_set_mac_type(struct e1000_hw *hw)
+{
+    DEBUGFUNC("e1000_set_mac_type");
+
+    switch (hw->device_id) {
+    case E1000_DEV_ID_82542:
+        switch (hw->revision_id) {
+        case E1000_82542_2_0_REV_ID:
+            hw->mac_type = e1000_82542_rev2_0;
+            break;
+        case E1000_82542_2_1_REV_ID:
+            hw->mac_type = e1000_82542_rev2_1;
+            break;
+        default:
+            /* Invalid 82542 revision ID */
+            return -E1000_ERR_MAC_TYPE;
+        }
+        break;
+    case E1000_DEV_ID_82543GC_FIBER:
+    case E1000_DEV_ID_82543GC_COPPER:
+        hw->mac_type = e1000_82543;
+        break;
+    case E1000_DEV_ID_82544EI_COPPER:
+    case E1000_DEV_ID_82544EI_FIBER:
+    case E1000_DEV_ID_82544GC_COPPER:
+    case E1000_DEV_ID_82544GC_LOM:
+        hw->mac_type = e1000_82544;
+        break;
+    case E1000_DEV_ID_82540EM:
+    case E1000_DEV_ID_82540EM_LOM:
+    case E1000_DEV_ID_82540EP:
+    case E1000_DEV_ID_82540EP_LOM:
+    case E1000_DEV_ID_82540EP_LP:
+        hw->mac_type = e1000_82540;
+        break;
+    case E1000_DEV_ID_82545EM_COPPER:
+    case E1000_DEV_ID_82545EM_FIBER:
+        hw->mac_type = e1000_82545;
+        break;
+    case E1000_DEV_ID_82546EB_COPPER:
+    case E1000_DEV_ID_82546EB_FIBER:
+        hw->mac_type = e1000_82546;
+        break;
+    default:
+        /* Should never have loaded on this device */
+        return -E1000_ERR_MAC_TYPE;
+    }
+    return E1000_SUCCESS;
+}
+/******************************************************************************
+ * Reset the transmit and receive units; mask and clear all interrupts.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+void
+e1000_reset_hw(struct e1000_hw *hw)
+{
+    uint32_t ctrl;
+    uint32_t ctrl_ext;
+    uint32_t icr;
+    uint32_t manc;
+
+    DEBUGFUNC("e1000_reset_hw");
+    /* For 82542 (rev 2.0), disable MWI before issuing a device reset */
+    if(hw->mac_type == e1000_82542_rev2_0) {
+        DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
+        e1000_pci_clear_mwi(hw);
+    }
+
+    /* Clear interrupt mask to stop board from generating interrupts */
+    DEBUGOUT("Masking off all interrupts\n");
+    E1000_WRITE_REG(hw, IMC, 0xffffffff);
+
+    /* Disable the Transmit and Receive units.  Then delay to allow
+     * any pending transactions to complete before we hit the MAC with
+     * the global reset.
+     */
+    E1000_WRITE_REG(hw, RCTL, 0);
+    E1000_WRITE_REG(hw, TCTL, E1000_TCTL_PSP);
+    E1000_WRITE_FLUSH(hw);
+
+    /* The tbi_compatibility_on Flag must be cleared when Rctl is cleared. */
+    hw->tbi_compatibility_on = FALSE;
+
+    /* Delay to allow any outstanding PCI transactions to complete before
+     * resetting the device
+     */ 
+    DEBUGOUT("Before delay\n");
+    msec_delay(10);
+
+    /* Issue a global reset to the MAC.  This will reset the chip's
+     * transmit, receive, DMA, and link units.  It will not effect
+     * the current PCI configuration.  The global reset bit is self-
+     * clearing, and should clear within a microsecond.
+     */
+    DEBUGOUT("Issuing a global reset to MAC\n");
+    ctrl = E1000_READ_REG(hw, CTRL);
+
+    if(hw->mac_type > e1000_82543)
+        E1000_WRITE_REG_IO(hw, CTRL, (ctrl | E1000_CTRL_RST));
+    else
+        E1000_WRITE_REG(hw, CTRL, (ctrl | E1000_CTRL_RST));
+
+    /* Force a reload from the EEPROM if necessary */
+    if(hw->mac_type < e1000_82540) {
+        /* Wait for reset to complete */
+        udelay(10);
+        ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+        ctrl_ext |= E1000_CTRL_EXT_EE_RST;
+        E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+        E1000_WRITE_FLUSH(hw);
+        /* Wait for EEPROM reload */
+        msec_delay(2);
+    } else {
+        /* Wait for EEPROM reload (it happens automatically) */
+        msec_delay(4);
+        /* Dissable HW ARPs on ASF enabled adapters */
+        manc = E1000_READ_REG(hw, MANC);
+        manc &= ~(E1000_MANC_ARP_EN);
+        E1000_WRITE_REG(hw, MANC, manc);
+    }
+    
+    /* Clear interrupt mask to stop board from generating interrupts */
+    DEBUGOUT("Masking off all interrupts\n");
+    E1000_WRITE_REG(hw, IMC, 0xffffffff);
+
+    /* Clear any pending interrupt events. */
+    icr = E1000_READ_REG(hw, ICR);
+
+    /* If MWI was previously enabled, reenable it. */
+    if(hw->mac_type == e1000_82542_rev2_0) {
+        if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
+            e1000_pci_set_mwi(hw);
+    }
+}
+
+/******************************************************************************
+ * Performs basic configuration of the adapter.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * 
+ * Assumes that the controller has previously been reset and is in a 
+ * post-reset uninitialized state. Initializes the receive address registers,
+ * multicast table, and VLAN filter table. Calls routines to setup link
+ * configuration and flow control settings. Clears all on-chip counters. Leaves
+ * the transmit and receive units disabled and uninitialized.
+ *****************************************************************************/
+int32_t
+e1000_init_hw(struct e1000_hw *hw)
+{
+    uint32_t ctrl, status;
+    uint32_t i;
+    int32_t ret_val;
+    uint16_t pcix_cmd_word;
+    uint16_t pcix_stat_hi_word;
+    uint16_t cmd_mmrbc;
+    uint16_t stat_mmrbc;
+
+    DEBUGFUNC("e1000_init_hw");
+
+    /* Initialize Identification LED */
+    ret_val = e1000_id_led_init(hw);
+    if(ret_val < 0) {
+        DEBUGOUT("Error Initializing Identification LED\n");
+        return ret_val;
+    }
+    
+    /* Set the Media Type and exit with error if it is not valid. */
+    if(hw->mac_type != e1000_82543) {
+        /* tbi_compatibility is only valid on 82543 */
+        hw->tbi_compatibility_en = FALSE;
+    }
+
+    if(hw->mac_type >= e1000_82543) {
+        status = E1000_READ_REG(hw, STATUS);
+        if(status & E1000_STATUS_TBIMODE) {
+            hw->media_type = e1000_media_type_fiber;
+            /* tbi_compatibility not valid on fiber */
+            hw->tbi_compatibility_en = FALSE;
+        } else {
+            hw->media_type = e1000_media_type_copper;
+        }
+    } else {
+        /* This is an 82542 (fiber only) */
+        hw->media_type = e1000_media_type_fiber;
+    }
+
+    /* Disabling VLAN filtering. */
+    DEBUGOUT("Initializing the IEEE VLAN\n");
+    E1000_WRITE_REG(hw, VET, 0);
+
+    e1000_clear_vfta(hw);
+
+    /* For 82542 (rev 2.0), disable MWI and put the receiver into reset */
+    if(hw->mac_type == e1000_82542_rev2_0) {
+        DEBUGOUT("Disabling MWI on 82542 rev 2.0\n");
+        e1000_pci_clear_mwi(hw);
+        E1000_WRITE_REG(hw, RCTL, E1000_RCTL_RST);
+        E1000_WRITE_FLUSH(hw);
+        msec_delay(5);
+    }
+
+    /* Setup the receive address. This involves initializing all of the Receive
+     * Address Registers (RARs 0 - 15).
+     */
+    e1000_init_rx_addrs(hw);
+
+    /* For 82542 (rev 2.0), take the receiver out of reset and enable MWI */
+    if(hw->mac_type == e1000_82542_rev2_0) {
+        E1000_WRITE_REG(hw, RCTL, 0);
+        E1000_WRITE_FLUSH(hw);
+        msec_delay(1);
+        if(hw->pci_cmd_word & CMD_MEM_WRT_INVALIDATE)
+            e1000_pci_set_mwi(hw);
+    }
+
+    /* Zero out the Multicast HASH table */
+    DEBUGOUT("Zeroing the MTA\n");
+    for(i = 0; i < E1000_MC_TBL_SIZE; i++)
+        E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
+
+    /* Set the PCI priority bit correctly in the CTRL register.  This
+     * determines if the adapter gives priority to receives, or if it
+     * gives equal priority to transmits and receives.
+     */
+    if(hw->dma_fairness) {
+        ctrl = E1000_READ_REG(hw, CTRL);
+        E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PRIOR);
+    }
+
+    /* Workaround for PCI-X problem when BIOS sets MMRBC incorrectly. */
+    if(hw->bus_type == e1000_bus_type_pcix) {
+        e1000_read_pci_cfg(hw, PCIX_COMMAND_REGISTER, &pcix_cmd_word);
+        e1000_read_pci_cfg(hw, PCIX_STATUS_REGISTER_HI, &pcix_stat_hi_word);
+        cmd_mmrbc = (pcix_cmd_word & PCIX_COMMAND_MMRBC_MASK) >>
+            PCIX_COMMAND_MMRBC_SHIFT;
+        stat_mmrbc = (pcix_stat_hi_word & PCIX_STATUS_HI_MMRBC_MASK) >>
+            PCIX_STATUS_HI_MMRBC_SHIFT;
+        if(stat_mmrbc == PCIX_STATUS_HI_MMRBC_4K)
+            stat_mmrbc = PCIX_STATUS_HI_MMRBC_2K;
+        if(cmd_mmrbc > stat_mmrbc) {
+            pcix_cmd_word &= ~PCIX_COMMAND_MMRBC_MASK;
+            pcix_cmd_word |= stat_mmrbc << PCIX_COMMAND_MMRBC_SHIFT;
+            e1000_write_pci_cfg(hw, PCIX_COMMAND_REGISTER, &pcix_cmd_word);
+        }
+    }
+
+    /* Call a subroutine to configure the link and setup flow control. */
+    ret_val = e1000_setup_link(hw);
+
+    /* Set the transmit descriptor write-back policy */
+    if(hw->mac_type > e1000_82544) {
+        ctrl = E1000_READ_REG(hw, TXDCTL);
+        ctrl = (ctrl & ~E1000_TXDCTL_WTHRESH) | E1000_TXDCTL_FULL_TX_DESC_WB;
+        E1000_WRITE_REG(hw, TXDCTL, ctrl);
+    }
+
+    /* Clear all of the statistics registers (clear on read).  It is
+     * important that we do this after we have tried to establish link
+     * because the symbol error count will increment wildly if there
+     * is no link.
+     */
+    e1000_clear_hw_cntrs(hw);
+
+    return ret_val;
+}
+
+/******************************************************************************
+ * Configures flow control and link settings.
+ * 
+ * hw - Struct containing variables accessed by shared code
+ * 
+ * Determines which flow control settings to use. Calls the apropriate media-
+ * specific link configuration function. Configures the flow control settings.
+ * Assuming the adapter has a valid link partner, a valid link should be
+ * established. Assumes the hardware has previously been reset and the 
+ * transmitter and receiver are not enabled.
+ *****************************************************************************/
+int32_t
+e1000_setup_link(struct e1000_hw *hw)
+{
+    uint32_t ctrl_ext;
+    int32_t ret_val;
+    uint16_t eeprom_data;
+
+    DEBUGFUNC("e1000_setup_link");
+
+    /* Read and store word 0x0F of the EEPROM. This word contains bits
+     * that determine the hardware's default PAUSE (flow control) mode,
+     * a bit that determines whether the HW defaults to enabling or
+     * disabling auto-negotiation, and the direction of the
+     * SW defined pins. If there is no SW over-ride of the flow
+     * control setting, then the variable hw->fc will
+     * be initialized based on a value in the EEPROM.
+     */
+    if(e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, &eeprom_data) < 0) {
+        DEBUGOUT("EEPROM Read Error\n");
+        return -E1000_ERR_EEPROM;
+    }
+
+    if(hw->fc == e1000_fc_default) {
+        if((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == 0)
+            hw->fc = e1000_fc_none;
+        else if((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == 
+                EEPROM_WORD0F_ASM_DIR)
+            hw->fc = e1000_fc_tx_pause;
+        else
+            hw->fc = e1000_fc_full;
+    }
+
+    /* We want to save off the original Flow Control configuration just
+     * in case we get disconnected and then reconnected into a different
+     * hub or switch with different Flow Control capabilities.
+     */
+    if(hw->mac_type == e1000_82542_rev2_0)
+        hw->fc &= (~e1000_fc_tx_pause);
+
+    if((hw->mac_type < e1000_82543) && (hw->report_tx_early == 1))
+        hw->fc &= (~e1000_fc_rx_pause);
+
+    hw->original_fc = hw->fc;
+
+    DEBUGOUT1("After fix-ups FlowControl is now = %x\n", hw->fc);
+
+    /* Take the 4 bits from EEPROM word 0x0F that determine the initial
+     * polarity value for the SW controlled pins, and setup the
+     * Extended Device Control reg with that info.
+     * This is needed because one of the SW controlled pins is used for
+     * signal detection.  So this should be done before e1000_setup_pcs_link()
+     * or e1000_phy_setup() is called.
+     */
+    if(hw->mac_type == e1000_82543) {
+        ctrl_ext = ((eeprom_data & EEPROM_WORD0F_SWPDIO_EXT) << 
+                    SWDPIO__EXT_SHIFT);
+        E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+    }
+
+    /* Call the necessary subroutine to configure the link. */
+    ret_val = (hw->media_type == e1000_media_type_fiber) ?
+              e1000_setup_fiber_link(hw) :
+              e1000_setup_copper_link(hw);
+
+    /* Initialize the flow control address, type, and PAUSE timer
+     * registers to their default values.  This is done even if flow
+     * control is disabled, because it does not hurt anything to
+     * initialize these registers.
+     */
+    DEBUGOUT("Initializing the Flow Control address, type and timer regs\n");
+
+    E1000_WRITE_REG(hw, FCAL, FLOW_CONTROL_ADDRESS_LOW);
+    E1000_WRITE_REG(hw, FCAH, FLOW_CONTROL_ADDRESS_HIGH);
+    E1000_WRITE_REG(hw, FCT, FLOW_CONTROL_TYPE);
+    E1000_WRITE_REG(hw, FCTTV, hw->fc_pause_time);
+
+    /* Set the flow control receive threshold registers.  Normally,
+     * these registers will be set to a default threshold that may be
+     * adjusted later by the driver's runtime code.  However, if the
+     * ability to transmit pause frames in not enabled, then these
+     * registers will be set to 0. 
+     */
+    if(!(hw->fc & e1000_fc_tx_pause)) {
+        E1000_WRITE_REG(hw, FCRTL, 0);
+        E1000_WRITE_REG(hw, FCRTH, 0);
+    } else {
+        /* We need to set up the Receive Threshold high and low water marks
+         * as well as (optionally) enabling the transmission of XON frames.
+         */
+        if(hw->fc_send_xon) {
+            E1000_WRITE_REG(hw, FCRTL, (hw->fc_low_water | E1000_FCRTL_XONE));
+            E1000_WRITE_REG(hw, FCRTH, hw->fc_high_water);
+        } else {
+            E1000_WRITE_REG(hw, FCRTL, hw->fc_low_water);
+            E1000_WRITE_REG(hw, FCRTH, hw->fc_high_water);
+        }
+    }
+    return ret_val;
+}
+
+/******************************************************************************
+ * Sets up link for a fiber based adapter
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Manipulates Physical Coding Sublayer functions in order to configure
+ * link. Assumes the hardware has been previously reset and the transmitter
+ * and receiver are not enabled.
+ *****************************************************************************/
+static int32_t 
+e1000_setup_fiber_link(struct e1000_hw *hw)
+{
+    uint32_t ctrl;
+    uint32_t status;
+    uint32_t txcw = 0;
+    uint32_t i;
+    uint32_t signal;
+    int32_t ret_val;
+
+    DEBUGFUNC("e1000_setup_fiber_link");
+
+    /* On adapters with a MAC newer that 82544, SW Defineable pin 1 will be 
+     * set when the optics detect a signal. On older adapters, it will be 
+     * cleared when there is a signal
+     */
+    ctrl = E1000_READ_REG(hw, CTRL);
+    if(hw->mac_type > e1000_82544) signal = E1000_CTRL_SWDPIN1;
+    else signal = 0;
+   
+    /* Take the link out of reset */
+    ctrl &= ~(E1000_CTRL_LRST);
+    
+    e1000_config_collision_dist(hw);
+
+    /* Check for a software override of the flow control settings, and setup
+     * the device accordingly.  If auto-negotiation is enabled, then software
+     * will have to set the "PAUSE" bits to the correct value in the Tranmsit
+     * Config Word Register (TXCW) and re-start auto-negotiation.  However, if
+     * auto-negotiation is disabled, then software will have to manually 
+     * configure the two flow control enable bits in the CTRL register.
+     *
+     * The possible values of the "fc" parameter are:
+     *      0:  Flow control is completely disabled
+     *      1:  Rx flow control is enabled (we can receive pause frames, but 
+     *          not send pause frames).
+     *      2:  Tx flow control is enabled (we can send pause frames but we do
+     *          not support receiving pause frames).
+     *      3:  Both Rx and TX flow control (symmetric) are enabled.
+     */
+    switch (hw->fc) {
+    case e1000_fc_none:
+        /* Flow control is completely disabled by a software over-ride. */
+        txcw = (E1000_TXCW_ANE | E1000_TXCW_FD);
+        break;
+    case e1000_fc_rx_pause:
+        /* RX Flow control is enabled and TX Flow control is disabled by a 
+         * software over-ride. Since there really isn't a way to advertise 
+         * that we are capable of RX Pause ONLY, we will advertise that we
+         * support both symmetric and asymmetric RX PAUSE. Later, we will
+         *  disable the adapter's ability to send PAUSE frames.
+         */
+        txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+        break;
+    case e1000_fc_tx_pause:
+        /* TX Flow control is enabled, and RX Flow control is disabled, by a 
+         * software over-ride.
+         */
+        txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR);
+        break;
+    case e1000_fc_full:
+        /* Flow control (both RX and TX) is enabled by a software over-ride. */
+        txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
+        break;
+    default:
+        DEBUGOUT("Flow control param set incorrectly\n");
+        return -E1000_ERR_CONFIG;
+        break;
+    }
+
+    /* Since auto-negotiation is enabled, take the link out of reset (the link
+     * will be in reset, because we previously reset the chip). This will
+     * restart auto-negotiation.  If auto-neogtiation is successful then the
+     * link-up status bit will be set and the flow control enable bits (RFCE
+     * and TFCE) will be set according to their negotiated value.
+     */
+    DEBUGOUT("Auto-negotiation enabled\n");
+
+    E1000_WRITE_REG(hw, TXCW, txcw);
+    E1000_WRITE_REG(hw, CTRL, ctrl);
+    E1000_WRITE_FLUSH(hw);
+
+    hw->txcw = txcw;
+    msec_delay(1);
+
+    /* If we have a signal (the cable is plugged in) then poll for a "Link-Up"
+     * indication in the Device Status Register.  Time-out if a link isn't 
+     * seen in 500 milliseconds seconds (Auto-negotiation should complete in 
+     * less than 500 milliseconds even if the other end is doing it in SW).
+     */
+    if((E1000_READ_REG(hw, CTRL) & E1000_CTRL_SWDPIN1) == signal) {
+        DEBUGOUT("Looking for Link\n");
+        for(i = 0; i < (LINK_UP_TIMEOUT / 10); i++) {
+            msec_delay(10);
+            status = E1000_READ_REG(hw, STATUS);
+            if(status & E1000_STATUS_LU) break;
+        }
+        if(i == (LINK_UP_TIMEOUT / 10)) {
+            /* AutoNeg failed to achieve a link, so we'll call 
+             * e1000_check_for_link. This routine will force the link up if we
+             * detect a signal. This will allow us to communicate with
+             * non-autonegotiating link partners.
+             */
+            DEBUGOUT("Never got a valid link from auto-neg!!!\n");
+            hw->autoneg_failed = 1;
+            ret_val = e1000_check_for_link(hw);
+            if(ret_val < 0) {
+                DEBUGOUT("Error while checking for link\n");
+                return ret_val;
+            }
+            hw->autoneg_failed = 0;
+        } else {
+            hw->autoneg_failed = 0;
+            DEBUGOUT("Valid Link Found\n");
+        }
+    } else {
+        DEBUGOUT("No Signal Detected\n");
+    }
+    return 0;
+}
+
+/******************************************************************************
+* Detects which PHY is present and the speed and duplex
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int32_t 
+e1000_setup_copper_link(struct e1000_hw *hw)
+{
+    uint32_t ctrl;
+    int32_t ret_val;
+    uint16_t i;
+    uint16_t phy_data;
+
+    DEBUGFUNC("e1000_setup_copper_link");
+
+    ctrl = E1000_READ_REG(hw, CTRL);
+    /* With 82543, we need to force speed and duplex on the MAC equal to what
+     * the PHY speed and duplex configuration is. In addition, we need to
+     * perform a hardware reset on the PHY to take it out of reset.
+     */
+    if(hw->mac_type > e1000_82543) {
+        ctrl |= E1000_CTRL_SLU;
+        ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+        E1000_WRITE_REG(hw, CTRL, ctrl);
+    } else {
+        ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX | E1000_CTRL_SLU);
+        E1000_WRITE_REG(hw, CTRL, ctrl);
+        e1000_phy_hw_reset(hw);
+    }
+
+    /* Make sure we have a valid PHY */
+    ret_val = e1000_detect_gig_phy(hw);
+    if(ret_val < 0) {
+        DEBUGOUT("Error, did not detect valid phy.\n");
+        return ret_val;
+    }
+    DEBUGOUT1("Phy ID = %x \n", hw->phy_id);
+
+    /* Enable CRS on TX. This must be set for half-duplex operation. */
+    if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+    phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+
+    /* Options:
+     *   MDI/MDI-X = 0 (default)
+     *   0 - Auto for all speeds
+     *   1 - MDI mode
+     *   2 - MDI-X mode
+     *   3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
+     */
+    phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+
+    switch (hw->mdix) {
+    case 1:
+        phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
+        break;
+    case 2:
+        phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
+        break;
+    case 3:
+        phy_data |= M88E1000_PSCR_AUTO_X_1000T;
+        break;
+    case 0:
+    default:
+        phy_data |= M88E1000_PSCR_AUTO_X_MODE;
+        break;
+    }
+
+    /* Options:
+     *   disable_polarity_correction = 0 (default)
+     *       Automatic Correction for Reversed Cable Polarity
+     *   0 - Disabled
+     *   1 - Enabled
+     */
+    phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
+    if(hw->disable_polarity_correction == 1)
+        phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
+    if(e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) {
+        DEBUGOUT("PHY Write Error\n");
+        return -E1000_ERR_PHY;
+    }
+
+    /* Force TX_CLK in the Extended PHY Specific Control Register
+     * to 25MHz clock.
+     */
+    if(e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+    phy_data |= M88E1000_EPSCR_TX_CLK_25;
+
+    if (hw->phy_revision < M88E1011_I_REV_4) {
+        /* Configure Master and Slave downshift values */
+        phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
+                      M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
+        phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
+                     M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
+        if(e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data) < 0) {
+            DEBUGOUT("PHY Write Error\n");
+            return -E1000_ERR_PHY;
+        }
+    }
+
+    /* SW Reset the PHY so all changes take effect */
+    ret_val = e1000_phy_reset(hw);
+    if(ret_val < 0) {
+        DEBUGOUT("Error Resetting the PHY\n");
+        return ret_val;
+    }
+    
+    /* Options:
+     *   autoneg = 1 (default)
+     *      PHY will advertise value(s) parsed from
+     *      autoneg_advertised and fc
+     *   autoneg = 0
+     *      PHY will be set to 10H, 10F, 100H, or 100F
+     *      depending on value parsed from forced_speed_duplex.
+     */
+
+    /* Is autoneg enabled?  This is enabled by default or by software override.
+     * If so, call e1000_phy_setup_autoneg routine to parse the
+     * autoneg_advertised and fc options. If autoneg is NOT enabled, then the
+     * user should have provided a speed/duplex override.  If so, then call
+     * e1000_phy_force_speed_duplex to parse and set this up.
+     */
+    if(hw->autoneg) {
+        /* Perform some bounds checking on the hw->autoneg_advertised
+         * parameter.  If this variable is zero, then set it to the default.
+         */
+        hw->autoneg_advertised &= AUTONEG_ADVERTISE_SPEED_DEFAULT;
+
+        /* If autoneg_advertised is zero, we assume it was not defaulted
+         * by the calling code so we set to advertise full capability.
+         */
+        if(hw->autoneg_advertised == 0)
+            hw->autoneg_advertised = AUTONEG_ADVERTISE_SPEED_DEFAULT;
+
+        DEBUGOUT("Reconfiguring auto-neg advertisement params\n");
+        ret_val = e1000_phy_setup_autoneg(hw);
+        if(ret_val < 0) {
+            DEBUGOUT("Error Setting up Auto-Negotiation\n");
+            return ret_val;
+        }
+        DEBUGOUT("Restarting Auto-Neg\n");
+
+        /* Restart auto-negotiation by setting the Auto Neg Enable bit and
+         * the Auto Neg Restart bit in the PHY control register.
+         */
+        if(e1000_read_phy_reg(hw, PHY_CTRL, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+        phy_data |= (MII_CR_AUTO_NEG_EN | MII_CR_RESTART_AUTO_NEG);
+        if(e1000_write_phy_reg(hw, PHY_CTRL, phy_data) < 0) {
+            DEBUGOUT("PHY Write Error\n");
+            return -E1000_ERR_PHY;
+        }
+
+        /* Does the user want to wait for Auto-Neg to complete here, or
+         * check at a later time (for example, callback routine).
+         */
+        if(hw->wait_autoneg_complete) {
+            ret_val = e1000_wait_autoneg(hw);
+            if(ret_val < 0) {
+                DEBUGOUT("Error while waiting for autoneg to complete\n");
+                return ret_val;
+            }
+        }
+    } else {
+        DEBUGOUT("Forcing speed and duplex\n");
+        ret_val = e1000_phy_force_speed_duplex(hw);
+        if(ret_val < 0) {
+            DEBUGOUT("Error Forcing Speed and Duplex\n");
+            return ret_val;
+        }
+    }
+
+    /* Check link status. Wait up to 100 microseconds for link to become
+     * valid.
+     */
+    for(i = 0; i < 10; i++) {
+        if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+        if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+        if(phy_data & MII_SR_LINK_STATUS) {
+            /* We have link, so we need to finish the config process:
+             *   1) Set up the MAC to the current PHY speed/duplex
+             *      if we are on 82543.  If we
+             *      are on newer silicon, we only need to configure
+             *      collision distance in the Transmit Control Register.
+             *   2) Set up flow control on the MAC to that established with
+             *      the link partner.
+             */
+            if(hw->mac_type >= e1000_82544) {
+                e1000_config_collision_dist(hw);
+            } else {
+                ret_val = e1000_config_mac_to_phy(hw);
+                if(ret_val < 0) {
+                    DEBUGOUT("Error configuring MAC to PHY settings\n");
+                    return ret_val;
+                  }
+            }
+            ret_val = e1000_config_fc_after_link_up(hw);
+            if(ret_val < 0) {
+                DEBUGOUT("Error Configuring Flow Control\n");
+                return ret_val;
+            }
+            DEBUGOUT("Valid link established!!!\n");
+            return 0;
+        }
+        udelay(10);
+    }
+
+    DEBUGOUT("Unable to establish link!!!\n");
+    return 0;
+}
+
+/******************************************************************************
+* Configures PHY autoneg and flow control advertisement settings
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+int32_t
+e1000_phy_setup_autoneg(struct e1000_hw *hw)
+{
+    uint16_t mii_autoneg_adv_reg;
+    uint16_t mii_1000t_ctrl_reg;
+
+    DEBUGFUNC("e1000_phy_setup_autoneg");
+
+    /* Read the MII Auto-Neg Advertisement Register (Address 4). */
+    if(e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &mii_autoneg_adv_reg) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+
+    /* Read the MII 1000Base-T Control Register (Address 9). */
+    if(e1000_read_phy_reg(hw, PHY_1000T_CTRL, &mii_1000t_ctrl_reg) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+
+    /* Need to parse both autoneg_advertised and fc and set up
+     * the appropriate PHY registers.  First we will parse for
+     * autoneg_advertised software override.  Since we can advertise
+     * a plethora of combinations, we need to check each bit
+     * individually.
+     */
+
+    /* First we clear all the 10/100 mb speed bits in the Auto-Neg
+     * Advertisement Register (Address 4) and the 1000 mb speed bits in
+     * the  1000Base-T Control Register (Address 9).
+     */
+    mii_autoneg_adv_reg &= ~REG4_SPEED_MASK;
+    mii_1000t_ctrl_reg &= ~REG9_SPEED_MASK;
+
+    DEBUGOUT1("autoneg_advertised %x\n", hw->autoneg_advertised);
+
+    /* Do we want to advertise 10 Mb Half Duplex? */
+    if(hw->autoneg_advertised & ADVERTISE_10_HALF) {
+        DEBUGOUT("Advertise 10mb Half duplex\n");
+        mii_autoneg_adv_reg |= NWAY_AR_10T_HD_CAPS;
+    }
+
+    /* Do we want to advertise 10 Mb Full Duplex? */
+    if(hw->autoneg_advertised & ADVERTISE_10_FULL) {
+        DEBUGOUT("Advertise 10mb Full duplex\n");
+        mii_autoneg_adv_reg |= NWAY_AR_10T_FD_CAPS;
+    }
+
+    /* Do we want to advertise 100 Mb Half Duplex? */
+    if(hw->autoneg_advertised & ADVERTISE_100_HALF) {
+        DEBUGOUT("Advertise 100mb Half duplex\n");
+        mii_autoneg_adv_reg |= NWAY_AR_100TX_HD_CAPS;
+    }
+
+    /* Do we want to advertise 100 Mb Full Duplex? */
+    if(hw->autoneg_advertised & ADVERTISE_100_FULL) {
+        DEBUGOUT("Advertise 100mb Full duplex\n");
+        mii_autoneg_adv_reg |= NWAY_AR_100TX_FD_CAPS;
+    }
+
+    /* We do not allow the Phy to advertise 1000 Mb Half Duplex */
+    if(hw->autoneg_advertised & ADVERTISE_1000_HALF) {
+        DEBUGOUT("Advertise 1000mb Half duplex requested, request denied!\n");
+    }
+
+    /* Do we want to advertise 1000 Mb Full Duplex? */
+    if(hw->autoneg_advertised & ADVERTISE_1000_FULL) {
+        DEBUGOUT("Advertise 1000mb Full duplex\n");
+        mii_1000t_ctrl_reg |= CR_1000T_FD_CAPS;
+    }
+
+    /* Check for a software override of the flow control settings, and
+     * setup the PHY advertisement registers accordingly.  If
+     * auto-negotiation is enabled, then software will have to set the
+     * "PAUSE" bits to the correct value in the Auto-Negotiation
+     * Advertisement Register (PHY_AUTONEG_ADV) and re-start auto-negotiation.
+     *
+     * The possible values of the "fc" parameter are:
+     *      0:  Flow control is completely disabled
+     *      1:  Rx flow control is enabled (we can receive pause frames
+     *          but not send pause frames).
+     *      2:  Tx flow control is enabled (we can send pause frames
+     *          but we do not support receiving pause frames).
+     *      3:  Both Rx and TX flow control (symmetric) are enabled.
+     *  other:  No software override.  The flow control configuration
+     *          in the EEPROM is used.
+     */
+    switch (hw->fc) {
+    case e1000_fc_none: /* 0 */
+        /* Flow control (RX & TX) is completely disabled by a
+         * software over-ride.
+         */
+        mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+        break;
+    case e1000_fc_rx_pause: /* 1 */
+        /* RX Flow control is enabled, and TX Flow control is
+         * disabled, by a software over-ride.
+         */
+        /* Since there really isn't a way to advertise that we are
+         * capable of RX Pause ONLY, we will advertise that we
+         * support both symmetric and asymmetric RX PAUSE.  Later
+         * (in e1000_config_fc_after_link_up) we will disable the
+         *hw's ability to send PAUSE frames.
+         */
+        mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+        break;
+    case e1000_fc_tx_pause: /* 2 */
+        /* TX Flow control is enabled, and RX Flow control is
+         * disabled, by a software over-ride.
+         */
+        mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
+        mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
+        break;
+    case e1000_fc_full: /* 3 */
+        /* Flow control (both RX and TX) is enabled by a software
+         * over-ride.
+         */
+        mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
+        break;
+    default:
+        DEBUGOUT("Flow control param set incorrectly\n");
+        return -E1000_ERR_CONFIG;
+    }
+
+    if(e1000_write_phy_reg(hw, PHY_AUTONEG_ADV, mii_autoneg_adv_reg) < 0) {
+        DEBUGOUT("PHY Write Error\n");
+        return -E1000_ERR_PHY;
+    }
+
+    DEBUGOUT1("Auto-Neg Advertising %x\n", mii_autoneg_adv_reg);
+
+    if(e1000_write_phy_reg(hw, PHY_1000T_CTRL, mii_1000t_ctrl_reg) < 0) {
+        DEBUGOUT("PHY Write Error\n");
+        return -E1000_ERR_PHY;
+    }
+    return 0;
+}
+
+/******************************************************************************
+* Force PHY speed and duplex settings to hw->forced_speed_duplex
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int32_t
+e1000_phy_force_speed_duplex(struct e1000_hw *hw)
+{
+    uint32_t ctrl;
+    int32_t ret_val;
+    uint16_t mii_ctrl_reg;
+    uint16_t mii_status_reg;
+    uint16_t phy_data;
+    uint16_t i;
+
+    DEBUGFUNC("e1000_phy_force_speed_duplex");
+
+    /* Turn off Flow control if we are forcing speed and duplex. */
+    hw->fc = e1000_fc_none;
+
+    DEBUGOUT1("hw->fc = %d\n", hw->fc);
+
+    /* Read the Device Control Register. */
+    ctrl = E1000_READ_REG(hw, CTRL);
+
+    /* Set the bits to Force Speed and Duplex in the Device Ctrl Reg. */
+    ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+    ctrl &= ~(DEVICE_SPEED_MASK);
+
+    /* Clear the Auto Speed Detect Enable bit. */
+    ctrl &= ~E1000_CTRL_ASDE;
+
+    /* Read the MII Control Register. */
+    if(e1000_read_phy_reg(hw, PHY_CTRL, &mii_ctrl_reg) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+
+    /* We need to disable autoneg in order to force link and duplex. */
+
+    mii_ctrl_reg &= ~MII_CR_AUTO_NEG_EN;
+
+    /* Are we forcing Full or Half Duplex? */
+    if(hw->forced_speed_duplex == e1000_100_full ||
+       hw->forced_speed_duplex == e1000_10_full) {
+        /* We want to force full duplex so we SET the full duplex bits in the
+         * Device and MII Control Registers.
+         */
+        ctrl |= E1000_CTRL_FD;
+        mii_ctrl_reg |= MII_CR_FULL_DUPLEX;
+        DEBUGOUT("Full Duplex\n");
+    } else {
+        /* We want to force half duplex so we CLEAR the full duplex bits in
+         * the Device and MII Control Registers.
+         */
+        ctrl &= ~E1000_CTRL_FD;
+        mii_ctrl_reg &= ~MII_CR_FULL_DUPLEX;
+        DEBUGOUT("Half Duplex\n");
+    }
+
+    /* Are we forcing 100Mbps??? */
+    if(hw->forced_speed_duplex == e1000_100_full ||
+       hw->forced_speed_duplex == e1000_100_half) {
+        /* Set the 100Mb bit and turn off the 1000Mb and 10Mb bits. */
+        ctrl |= E1000_CTRL_SPD_100;
+        mii_ctrl_reg |= MII_CR_SPEED_100;
+        mii_ctrl_reg &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_10);
+        DEBUGOUT("Forcing 100mb ");
+    } else {
+        /* Set the 10Mb bit and turn off the 1000Mb and 100Mb bits. */
+        ctrl &= ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
+        mii_ctrl_reg |= MII_CR_SPEED_10;
+        mii_ctrl_reg &= ~(MII_CR_SPEED_1000 | MII_CR_SPEED_100);
+        DEBUGOUT("Forcing 10mb ");
+    }
+
+    e1000_config_collision_dist(hw);
+
+    /* Write the configured values back to the Device Control Reg. */
+    E1000_WRITE_REG(hw, CTRL, ctrl);
+
+    if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+
+    /* Clear Auto-Crossover to force MDI manually. M88E1000 requires MDI
+     * forced whenever speed are duplex are forced.
+     */
+    phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+    if(e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) {
+        DEBUGOUT("PHY Write Error\n");
+        return -E1000_ERR_PHY;
+    }
+    DEBUGOUT1("M88E1000 PSCR: %x \n", phy_data);
+
+    /* Need to reset the PHY or these changes will be ignored */
+    mii_ctrl_reg |= MII_CR_RESET;
+
+    /* Write back the modified PHY MII control register. */
+    if(e1000_write_phy_reg(hw, PHY_CTRL, mii_ctrl_reg) < 0) {
+        DEBUGOUT("PHY Write Error\n");
+        return -E1000_ERR_PHY;
+    }
+    udelay(1);
+
+    /* The wait_autoneg_complete flag may be a little misleading here.
+     * Since we are forcing speed and duplex, Auto-Neg is not enabled.
+     * But we do want to delay for a period while forcing only so we
+     * don't generate false No Link messages.  So we will wait here
+     * only if the user has set wait_autoneg_complete to 1, which is
+     * the default.
+     */
+    if(hw->wait_autoneg_complete) {
+        /* We will wait for autoneg to complete. */
+        DEBUGOUT("Waiting for forced speed/duplex link.\n");
+        mii_status_reg = 0;
+
+        /* We will wait for autoneg to complete or 4.5 seconds to expire. */
+        for(i = PHY_FORCE_TIME; i > 0; i--) {
+            /* Read the MII Status Register and wait for Auto-Neg Complete bit
+             * to be set.
+             */
+            if(e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
+                DEBUGOUT("PHY Read Error\n");
+                return -E1000_ERR_PHY;
+            }
+            if(e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
+                DEBUGOUT("PHY Read Error\n");
+                return -E1000_ERR_PHY;
+            }
+            if(mii_status_reg & MII_SR_LINK_STATUS) break;
+            msec_delay(100);
+        }
+        if(i == 0) { /* We didn't get link */
+            /* Reset the DSP and wait again for link. */
+            
+            ret_val = e1000_phy_reset_dsp(hw);
+            if(ret_val < 0) {
+                DEBUGOUT("Error Resetting PHY DSP\n");
+                return ret_val;
+            }
+        }
+        /* This loop will early-out if the link condition has been met.  */
+        for(i = PHY_FORCE_TIME; i > 0; i--) {
+            if(mii_status_reg & MII_SR_LINK_STATUS) break;
+            msec_delay(100);
+            /* Read the MII Status Register and wait for Auto-Neg Complete bit
+             * to be set.
+             */
+            if(e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
+                DEBUGOUT("PHY Read Error\n");
+                return -E1000_ERR_PHY;
+            }
+            if(e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
+                DEBUGOUT("PHY Read Error\n");
+                return -E1000_ERR_PHY;
+            }
+        }
+    }
+    
+    /* Because we reset the PHY above, we need to re-force TX_CLK in the
+     * Extended PHY Specific Control Register to 25MHz clock.  This value
+     * defaults back to a 2.5MHz clock when the PHY is reset.
+     */
+    if(e1000_read_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, &phy_data) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+    phy_data |= M88E1000_EPSCR_TX_CLK_25;
+    if(e1000_write_phy_reg(hw, M88E1000_EXT_PHY_SPEC_CTRL, phy_data) < 0) {
+        DEBUGOUT("PHY Write Error\n");
+        return -E1000_ERR_PHY;
+    }
+
+    /* In addition, because of the s/w reset above, we need to enable CRS on
+     * TX.  This must be set for both full and half duplex operation.
+     */
+    if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+    phy_data |= M88E1000_PSCR_ASSERT_CRS_ON_TX;
+    if(e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data) < 0) {
+        DEBUGOUT("PHY Write Error\n");
+        return -E1000_ERR_PHY;
+    }
+    return 0;
+}
+
+/******************************************************************************
+* Sets the collision distance in the Transmit Control register
+*
+* hw - Struct containing variables accessed by shared code
+*
+* Link should have been established previously. Reads the speed and duplex
+* information from the Device Status register.
+******************************************************************************/
+void
+e1000_config_collision_dist(struct e1000_hw *hw)
+{
+    uint32_t tctl;
+
+    tctl = E1000_READ_REG(hw, TCTL);
+
+    tctl &= ~E1000_TCTL_COLD;
+    tctl |= E1000_COLLISION_DISTANCE << E1000_COLD_SHIFT;
+
+    E1000_WRITE_REG(hw, TCTL, tctl);
+    E1000_WRITE_FLUSH(hw);
+}
+
+/******************************************************************************
+* Sets MAC speed and duplex settings to reflect the those in the PHY
+*
+* hw - Struct containing variables accessed by shared code
+* mii_reg - data to write to the MII control register
+*
+* The contents of the PHY register containing the needed information need to
+* be passed in.
+******************************************************************************/
+static int32_t
+e1000_config_mac_to_phy(struct e1000_hw *hw)
+{
+    uint32_t ctrl;
+    uint16_t phy_data;
+
+    DEBUGFUNC("e1000_config_mac_to_phy");
+
+    /* Read the Device Control Register and set the bits to Force Speed
+     * and Duplex.
+     */
+    ctrl = E1000_READ_REG(hw, CTRL);
+    ctrl |= (E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+    ctrl &= ~(E1000_CTRL_SPD_SEL | E1000_CTRL_ILOS);
+
+    /* Set up duplex in the Device Control and Transmit Control
+     * registers depending on negotiated values.
+     */
+    if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+    if(phy_data & M88E1000_PSSR_DPLX) ctrl |= E1000_CTRL_FD;
+    else ctrl &= ~E1000_CTRL_FD;
+
+    e1000_config_collision_dist(hw);
+
+    /* Set up speed in the Device Control register depending on
+     * negotiated values.
+     */
+    if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS)
+        ctrl |= E1000_CTRL_SPD_1000;
+    else if((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS)
+        ctrl |= E1000_CTRL_SPD_100;
+    /* Write the configured values back to the Device Control Reg. */
+    E1000_WRITE_REG(hw, CTRL, ctrl);
+    return 0;
+}
+
+/******************************************************************************
+ * Forces the MAC's flow control settings.
+ * 
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Sets the TFCE and RFCE bits in the device control register to reflect
+ * the adapter settings. TFCE and RFCE need to be explicitly set by
+ * software when a Copper PHY is used because autonegotiation is managed
+ * by the PHY rather than the MAC. Software must also configure these
+ * bits when link is forced on a fiber connection.
+ *****************************************************************************/
+static int32_t
+e1000_force_mac_fc(struct e1000_hw *hw)
+{
+    uint32_t ctrl;
+
+    DEBUGFUNC("e1000_force_mac_fc");
+
+    /* Get the current configuration of the Device Control Register */
+    ctrl = E1000_READ_REG(hw, CTRL);
+
+    /* Because we didn't get link via the internal auto-negotiation
+     * mechanism (we either forced link or we got link via PHY
+     * auto-neg), we have to manually enable/disable transmit an
+     * receive flow control.
+     *
+     * The "Case" statement below enables/disable flow control
+     * according to the "hw->fc" parameter.
+     *
+     * The possible values of the "fc" parameter are:
+     *      0:  Flow control is completely disabled
+     *      1:  Rx flow control is enabled (we can receive pause
+     *          frames but not send pause frames).
+     *      2:  Tx flow control is enabled (we can send pause frames
+     *          frames but we do not receive pause frames).
+     *      3:  Both Rx and TX flow control (symmetric) is enabled.
+     *  other:  No other values should be possible at this point.
+     */
+
+    switch (hw->fc) {
+    case e1000_fc_none:
+        ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE));
+        break;
+    case e1000_fc_rx_pause:
+        ctrl &= (~E1000_CTRL_TFCE);
+        ctrl |= E1000_CTRL_RFCE;
+        break;
+    case e1000_fc_tx_pause:
+        ctrl &= (~E1000_CTRL_RFCE);
+        ctrl |= E1000_CTRL_TFCE;
+        break;
+    case e1000_fc_full:
+        ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE);
+        break;
+    default:
+        DEBUGOUT("Flow control param set incorrectly\n");
+        return -E1000_ERR_CONFIG;
+    }
+
+    /* Disable TX Flow Control for 82542 (rev 2.0) */
+    if(hw->mac_type == e1000_82542_rev2_0)
+        ctrl &= (~E1000_CTRL_TFCE);
+
+    E1000_WRITE_REG(hw, CTRL, ctrl);
+    return 0;
+}
+
+/******************************************************************************
+ * Configures flow control settings after link is established
+ * 
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Should be called immediately after a valid link has been established.
+ * Forces MAC flow control settings if link was forced. When in MII/GMII mode
+ * and autonegotiation is enabled, the MAC flow control settings will be set
+ * based on the flow control negotiated by the PHY. In TBI mode, the TFCE
+ * and RFCE bits will be automaticaly set to the negotiated flow control mode.
+ *****************************************************************************/
+int32_t
+e1000_config_fc_after_link_up(struct e1000_hw *hw)
+{
+    int32_t ret_val;
+    uint16_t mii_status_reg;
+    uint16_t mii_nway_adv_reg;
+    uint16_t mii_nway_lp_ability_reg;
+    uint16_t speed;
+    uint16_t duplex;
+
+    DEBUGFUNC("e1000_config_fc_after_link_up");
+
+    /* Check for the case where we have fiber media and auto-neg failed
+     * so we had to force link.  In this case, we need to force the
+     * configuration of the MAC to match the "fc" parameter.
+     */
+    if(((hw->media_type == e1000_media_type_fiber) && (hw->autoneg_failed)) ||
+       ((hw->media_type == e1000_media_type_copper) && (!hw->autoneg))) {
+        ret_val = e1000_force_mac_fc(hw);
+        if(ret_val < 0) {
+            DEBUGOUT("Error forcing flow control settings\n");
+            return ret_val;
+        }
+    }
+
+    /* Check for the case where we have copper media and auto-neg is
+     * enabled.  In this case, we need to check and see if Auto-Neg
+     * has completed, and if so, how the PHY and link partner has
+     * flow control configured.
+     */
+    if((hw->media_type == e1000_media_type_copper) && hw->autoneg) {
+        /* Read the MII Status Register and check to see if AutoNeg
+         * has completed.  We read this twice because this reg has
+         * some "sticky" (latched) bits.
+         */
+        if(e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
+            DEBUGOUT("PHY Read Error \n");
+            return -E1000_ERR_PHY;
+        }
+        if(e1000_read_phy_reg(hw, PHY_STATUS, &mii_status_reg) < 0) {
+            DEBUGOUT("PHY Read Error \n");
+            return -E1000_ERR_PHY;
+        }
+
+        if(mii_status_reg & MII_SR_AUTONEG_COMPLETE) {
+            /* The AutoNeg process has completed, so we now need to
+             * read both the Auto Negotiation Advertisement Register
+             * (Address 4) and the Auto_Negotiation Base Page Ability
+             * Register (Address 5) to determine how flow control was
+             * negotiated.
+             */
+            if(e1000_read_phy_reg(hw, PHY_AUTONEG_ADV, &mii_nway_adv_reg) < 0) {
+                DEBUGOUT("PHY Read Error\n");
+                return -E1000_ERR_PHY;
+            }
+            if(e1000_read_phy_reg(hw, PHY_LP_ABILITY, &mii_nway_lp_ability_reg) < 0) {
+                DEBUGOUT("PHY Read Error\n");
+                return -E1000_ERR_PHY;
+            }
+
+            /* Two bits in the Auto Negotiation Advertisement Register
+             * (Address 4) and two bits in the Auto Negotiation Base
+             * Page Ability Register (Address 5) determine flow control
+             * for both the PHY and the link partner.  The following
+             * table, taken out of the IEEE 802.3ab/D6.0 dated March 25,
+             * 1999, describes these PAUSE resolution bits and how flow
+             * control is determined based upon these settings.
+             * NOTE:  DC = Don't Care
+             *
+             *   LOCAL DEVICE  |   LINK PARTNER
+             * PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
+             *-------|---------|-------|---------|--------------------
+             *   0   |    0    |  DC   |   DC    | e1000_fc_none
+             *   0   |    1    |   0   |   DC    | e1000_fc_none
+             *   0   |    1    |   1   |    0    | e1000_fc_none
+             *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
+             *   1   |    0    |   0   |   DC    | e1000_fc_none
+             *   1   |   DC    |   1   |   DC    | e1000_fc_full
+             *   1   |    1    |   0   |    0    | e1000_fc_none
+             *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
+             *
+             */
+            /* Are both PAUSE bits set to 1?  If so, this implies
+             * Symmetric Flow Control is enabled at both ends.  The
+             * ASM_DIR bits are irrelevant per the spec.
+             *
+             * For Symmetric Flow Control:
+             *
+             *   LOCAL DEVICE  |   LINK PARTNER
+             * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+             *-------|---------|-------|---------|--------------------
+             *   1   |   DC    |   1   |   DC    | e1000_fc_full
+             *
+             */
+            if((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+               (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE)) {
+                /* Now we need to check if the user selected RX ONLY
+                 * of pause frames.  In this case, we had to advertise
+                 * FULL flow control because we could not advertise RX
+                 * ONLY. Hence, we must now check to see if we need to
+                 * turn OFF  the TRANSMISSION of PAUSE frames.
+                 */
+                if(hw->original_fc == e1000_fc_full) {
+                    hw->fc = e1000_fc_full;
+                    DEBUGOUT("Flow Control = FULL.\r\n");
+                } else {
+                    hw->fc = e1000_fc_rx_pause;
+                    DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
+                }
+            }
+            /* For receiving PAUSE frames ONLY.
+             *
+             *   LOCAL DEVICE  |   LINK PARTNER
+             * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+             *-------|---------|-------|---------|--------------------
+             *   0   |    1    |   1   |    1    | e1000_fc_tx_pause
+             *
+             */
+            else if(!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+                    (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+                    (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+                    (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+                hw->fc = e1000_fc_tx_pause;
+                DEBUGOUT("Flow Control = TX PAUSE frames only.\r\n");
+            }
+            /* For transmitting PAUSE frames ONLY.
+             *
+             *   LOCAL DEVICE  |   LINK PARTNER
+             * PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
+             *-------|---------|-------|---------|--------------------
+             *   1   |    1    |   0   |    1    | e1000_fc_rx_pause
+             *
+             */
+            else if((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
+                    (mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
+                    !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
+                    (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
+                hw->fc = e1000_fc_rx_pause;
+                DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
+            }
+            /* Per the IEEE spec, at this point flow control should be
+             * disabled.  However, we want to consider that we could
+             * be connected to a legacy switch that doesn't advertise
+             * desired flow control, but can be forced on the link
+             * partner.  So if we advertised no flow control, that is
+             * what we will resolve to.  If we advertised some kind of
+             * receive capability (Rx Pause Only or Full Flow Control)
+             * and the link partner advertised none, we will configure
+             * ourselves to enable Rx Flow Control only.  We can do
+             * this safely for two reasons:  If the link partner really
+             * didn't want flow control enabled, and we enable Rx, no
+             * harm done since we won't be receiving any PAUSE frames
+             * anyway.  If the intent on the link partner was to have
+             * flow control enabled, then by us enabling RX only, we
+             * can at least receive pause frames and process them.
+             * This is a good idea because in most cases, since we are
+             * predominantly a server NIC, more times than not we will
+             * be asked to delay transmission of packets than asking
+             * our link partner to pause transmission of frames.
+             */
+            else if(hw->original_fc == e1000_fc_none ||
+                    hw->original_fc == e1000_fc_tx_pause) {
+                hw->fc = e1000_fc_none;
+                DEBUGOUT("Flow Control = NONE.\r\n");
+            } else {
+                hw->fc = e1000_fc_rx_pause;
+                DEBUGOUT("Flow Control = RX PAUSE frames only.\r\n");
+            }
+
+            /* Now we need to do one last check...  If we auto-
+             * negotiated to HALF DUPLEX, flow control should not be
+             * enabled per IEEE 802.3 spec.
+             */
+            e1000_get_speed_and_duplex(hw, &speed, &duplex);
+
+            if(duplex == HALF_DUPLEX)
+                hw->fc = e1000_fc_none;
+
+            /* Now we call a subroutine to actually force the MAC
+             * controller to use the correct flow control settings.
+             */
+            ret_val = e1000_force_mac_fc(hw);
+            if(ret_val < 0) {
+                DEBUGOUT("Error forcing flow control settings\n");
+                return ret_val;
+             }
+        } else {
+            DEBUGOUT("Copper PHY and Auto Neg has not completed.\r\n");
+        }
+    }
+    return 0;
+}
+
+/******************************************************************************
+ * Checks to see if the link status of the hardware has changed.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Called by any function that needs to check the link status of the adapter.
+ *****************************************************************************/
+int32_t
+e1000_check_for_link(struct e1000_hw *hw)
+{
+    uint32_t rxcw;
+    uint32_t ctrl;
+    uint32_t status;
+    uint32_t rctl;
+    uint32_t signal;
+    int32_t ret_val;
+    uint16_t phy_data;
+    uint16_t lp_capability;
+
+    DEBUGFUNC("e1000_check_for_link");
+    
+    /* On adapters with a MAC newer that 82544, SW Defineable pin 1 will be 
+     * set when the optics detect a signal. On older adapters, it will be 
+     * cleared when there is a signal
+     */
+    if(hw->mac_type > e1000_82544) signal = E1000_CTRL_SWDPIN1;
+    else signal = 0;
+
+    ctrl = E1000_READ_REG(hw, CTRL);
+    status = E1000_READ_REG(hw, STATUS);
+    rxcw = E1000_READ_REG(hw, RXCW);
+
+    /* If we have a copper PHY then we only want to go out to the PHY
+     * registers to see if Auto-Neg has completed and/or if our link
+     * status has changed.  The get_link_status flag will be set if we
+     * receive a Link Status Change interrupt or we have Rx Sequence
+     * Errors.
+     */
+    if((hw->media_type == e1000_media_type_copper) && hw->get_link_status) {
+        /* First we want to see if the MII Status Register reports
+         * link.  If so, then we want to get the current speed/duplex
+         * of the PHY.
+         * Read the register twice since the link bit is sticky.
+         */
+        if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+        if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+
+        if(phy_data & MII_SR_LINK_STATUS) {
+            hw->get_link_status = FALSE;
+        } else {
+            /* No link detected */
+            return 0;
+        }
+
+        /* If we are forcing speed/duplex, then we simply return since
+         * we have already determined whether we have link or not.
+         */
+        if(!hw->autoneg) return -E1000_ERR_CONFIG;
+
+        /* We have a M88E1000 PHY and Auto-Neg is enabled.  If we
+         * have Si on board that is 82544 or newer, Auto
+         * Speed Detection takes care of MAC speed/duplex
+         * configuration.  So we only need to configure Collision
+         * Distance in the MAC.  Otherwise, we need to force
+         * speed/duplex on the MAC to the current PHY speed/duplex
+         * settings.
+         */
+        if(hw->mac_type >= e1000_82544)
+            e1000_config_collision_dist(hw);
+        else {
+            ret_val = e1000_config_mac_to_phy(hw);
+            if(ret_val < 0) {
+                DEBUGOUT("Error configuring MAC to PHY settings\n");
+                return ret_val;
+            }
+        }
+
+        /* Configure Flow Control now that Auto-Neg has completed. First, we 
+         * need to restore the desired flow control settings because we may
+         * have had to re-autoneg with a different link partner.
+         */
+        ret_val = e1000_config_fc_after_link_up(hw);
+        if(ret_val < 0) {
+            DEBUGOUT("Error configuring flow control\n");
+            return ret_val;
+        }
+
+        /* At this point we know that we are on copper and we have
+         * auto-negotiated link.  These are conditions for checking the link
+         * parter capability register.  We use the link partner capability to
+         * determine if TBI Compatibility needs to be turned on or off.  If
+         * the link partner advertises any speed in addition to Gigabit, then
+         * we assume that they are GMII-based, and TBI compatibility is not
+         * needed. If no other speeds are advertised, we assume the link
+         * partner is TBI-based, and we turn on TBI Compatibility.
+         */
+        if(hw->tbi_compatibility_en) {
+            if(e1000_read_phy_reg(hw, PHY_LP_ABILITY, &lp_capability) < 0) {
+                DEBUGOUT("PHY Read Error\n");
+                return -E1000_ERR_PHY;
+            }
+            if(lp_capability & (NWAY_LPAR_10T_HD_CAPS |
+                                NWAY_LPAR_10T_FD_CAPS |
+                                NWAY_LPAR_100TX_HD_CAPS |
+                                NWAY_LPAR_100TX_FD_CAPS |
+                                NWAY_LPAR_100T4_CAPS)) {
+                /* If our link partner advertises anything in addition to 
+                 * gigabit, we do not need to enable TBI compatibility.
+                 */
+                if(hw->tbi_compatibility_on) {
+                    /* If we previously were in the mode, turn it off. */
+                    rctl = E1000_READ_REG(hw, RCTL);
+                    rctl &= ~E1000_RCTL_SBP;
+                    E1000_WRITE_REG(hw, RCTL, rctl);
+                    hw->tbi_compatibility_on = FALSE;
+                }
+            } else {
+                /* If TBI compatibility is was previously off, turn it on. For
+                 * compatibility with a TBI link partner, we will store bad
+                 * packets. Some frames have an additional byte on the end and
+                 * will look like CRC errors to to the hardware.
+                 */
+                if(!hw->tbi_compatibility_on) {
+                    hw->tbi_compatibility_on = TRUE;
+                    rctl = E1000_READ_REG(hw, RCTL);
+                    rctl |= E1000_RCTL_SBP;
+                    E1000_WRITE_REG(hw, RCTL, rctl);
+                }
+            }
+        }
+    }
+    /* If we don't have link (auto-negotiation failed or link partner cannot
+     * auto-negotiate), the cable is plugged in (we have signal), and our
+     * link partner is not trying to auto-negotiate with us (we are receiving
+     * idles or data), we need to force link up. We also need to give
+     * auto-negotiation time to complete, in case the cable was just plugged
+     * in. The autoneg_failed flag does this.
+     */
+    else if((hw->media_type == e1000_media_type_fiber) &&
+            (!(status & E1000_STATUS_LU)) &&
+            ((ctrl & E1000_CTRL_SWDPIN1) == signal) &&
+            (!(rxcw & E1000_RXCW_C))) {
+        if(hw->autoneg_failed == 0) {
+            hw->autoneg_failed = 1;
+            return 0;
+        }
+        DEBUGOUT("NOT RXing /C/, disable AutoNeg and force link.\r\n");
+
+        /* Disable auto-negotiation in the TXCW register */
+        E1000_WRITE_REG(hw, TXCW, (hw->txcw & ~E1000_TXCW_ANE));
+
+        /* Force link-up and also force full-duplex. */
+        ctrl = E1000_READ_REG(hw, CTRL);
+        ctrl |= (E1000_CTRL_SLU | E1000_CTRL_FD);
+        E1000_WRITE_REG(hw, CTRL, ctrl);
+
+        /* Configure Flow Control after forcing link up. */
+        ret_val = e1000_config_fc_after_link_up(hw);
+        if(ret_val < 0) {
+            DEBUGOUT("Error configuring flow control\n");
+            return ret_val;
+        }
+    }
+    /* If we are forcing link and we are receiving /C/ ordered sets, re-enable
+     * auto-negotiation in the TXCW register and disable forced link in the
+     * Device Control register in an attempt to auto-negotiate with our link
+     * partner.
+     */
+    else if((hw->media_type == e1000_media_type_fiber) &&
+              (ctrl & E1000_CTRL_SLU) &&
+              (rxcw & E1000_RXCW_C)) {
+        DEBUGOUT("RXing /C/, enable AutoNeg and stop forcing link.\r\n");
+        E1000_WRITE_REG(hw, TXCW, hw->txcw);
+        E1000_WRITE_REG(hw, CTRL, (ctrl & ~E1000_CTRL_SLU));
+    }
+    return 0;
+}
+
+/******************************************************************************
+ * Detects the current speed and duplex settings of the hardware.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * speed - Speed of the connection
+ * duplex - Duplex setting of the connection
+ *****************************************************************************/
+void
+e1000_get_speed_and_duplex(struct e1000_hw *hw,
+                           uint16_t *speed,
+                           uint16_t *duplex)
+{
+    uint32_t status;
+
+    DEBUGFUNC("e1000_get_speed_and_duplex");
+
+    if(hw->mac_type >= e1000_82543) {
+        status = E1000_READ_REG(hw, STATUS);
+        if(status & E1000_STATUS_SPEED_1000) {
+            *speed = SPEED_1000;
+            DEBUGOUT("1000 Mbs, ");
+        } else if(status & E1000_STATUS_SPEED_100) {
+            *speed = SPEED_100;
+            DEBUGOUT("100 Mbs, ");
+        } else {
+            *speed = SPEED_10;
+            DEBUGOUT("10 Mbs, ");
+        }
+
+        if(status & E1000_STATUS_FD) {
+            *duplex = FULL_DUPLEX;
+            DEBUGOUT("Full Duplex\r\n");
+        } else {
+            *duplex = HALF_DUPLEX;
+            DEBUGOUT(" Half Duplex\r\n");
+        }
+    } else {
+        DEBUGOUT("1000 Mbs, Full Duplex\r\n");
+        *speed = SPEED_1000;
+        *duplex = FULL_DUPLEX;
+    }
+}
+
+/******************************************************************************
+* Blocks until autoneg completes or times out (~4.5 seconds)
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+int32_t
+e1000_wait_autoneg(struct e1000_hw *hw)
+{
+    uint16_t i;
+    uint16_t phy_data;
+
+    DEBUGFUNC("e1000_wait_autoneg");
+    DEBUGOUT("Waiting for Auto-Neg to complete.\n");
+
+    /* We will wait for autoneg to complete or 4.5 seconds to expire. */
+    for(i = PHY_AUTO_NEG_TIME; i > 0; i--) {
+        /* Read the MII Status Register and wait for Auto-Neg
+         * Complete bit to be set.
+         */
+        if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+        if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) {
+            DEBUGOUT("PHY Read Error\n");
+            return -E1000_ERR_PHY;
+        }
+        if(phy_data & MII_SR_AUTONEG_COMPLETE) {
+            return 0;
+        }
+        msec_delay(100);
+    }
+    return 0;
+}
+
+/******************************************************************************
+* Raises the Management Data Clock
+*
+* hw - Struct containing variables accessed by shared code
+* ctrl - Device control register's current value
+******************************************************************************/
+static void
+e1000_raise_mdi_clk(struct e1000_hw *hw,
+                    uint32_t *ctrl)
+{
+    /* Raise the clock input to the Management Data Clock (by setting the MDC
+     * bit), and then delay 2 microseconds.
+     */
+    E1000_WRITE_REG(hw, CTRL, (*ctrl | E1000_CTRL_MDC));
+    E1000_WRITE_FLUSH(hw);
+    udelay(2);
+}
+
+/******************************************************************************
+* Lowers the Management Data Clock
+*
+* hw - Struct containing variables accessed by shared code
+* ctrl - Device control register's current value
+******************************************************************************/
+static void
+e1000_lower_mdi_clk(struct e1000_hw *hw,
+                    uint32_t *ctrl)
+{
+    /* Lower the clock input to the Management Data Clock (by clearing the MDC
+     * bit), and then delay 2 microseconds.
+     */
+    E1000_WRITE_REG(hw, CTRL, (*ctrl & ~E1000_CTRL_MDC));
+    E1000_WRITE_FLUSH(hw);
+    udelay(2);
+}
+
+/******************************************************************************
+* Shifts data bits out to the PHY
+*
+* hw - Struct containing variables accessed by shared code
+* data - Data to send out to the PHY
+* count - Number of bits to shift out
+*
+* Bits are shifted out in MSB to LSB order.
+******************************************************************************/
+static void
+e1000_shift_out_mdi_bits(struct e1000_hw *hw,
+                         uint32_t data,
+                         uint16_t count)
+{
+    uint32_t ctrl;
+    uint32_t mask;
+
+    /* We need to shift "count" number of bits out to the PHY. So, the value
+     * in the "data" parameter will be shifted out to the PHY one bit at a 
+     * time. In order to do this, "data" must be broken down into bits.
+     */
+    mask = 0x01;
+    mask <<= (count - 1);
+
+    ctrl = E1000_READ_REG(hw, CTRL);
+
+    /* Set MDIO_DIR and MDC_DIR direction bits to be used as output pins. */
+    ctrl |= (E1000_CTRL_MDIO_DIR | E1000_CTRL_MDC_DIR);
+
+    while(mask) {
+        /* A "1" is shifted out to the PHY by setting the MDIO bit to "1" and
+         * then raising and lowering the Management Data Clock. A "0" is
+         * shifted out to the PHY by setting the MDIO bit to "0" and then
+         * raising and lowering the clock.
+         */
+        if(data & mask) ctrl |= E1000_CTRL_MDIO;
+        else ctrl &= ~E1000_CTRL_MDIO;
+
+        E1000_WRITE_REG(hw, CTRL, ctrl);
+        E1000_WRITE_FLUSH(hw);
+
+        udelay(2);
+
+        e1000_raise_mdi_clk(hw, &ctrl);
+        e1000_lower_mdi_clk(hw, &ctrl);
+
+        mask = mask >> 1;
+    }
+}
+
+/******************************************************************************
+* Shifts data bits in from the PHY
+*
+* hw - Struct containing variables accessed by shared code
+*
+* Bits are shifted in in MSB to LSB order. 
+******************************************************************************/
+static uint16_t
+e1000_shift_in_mdi_bits(struct e1000_hw *hw)
+{
+    uint32_t ctrl;
+    uint16_t data = 0;
+    uint8_t i;
+
+    /* In order to read a register from the PHY, we need to shift in a total
+     * of 18 bits from the PHY. The first two bit (turnaround) times are used
+     * to avoid contention on the MDIO pin when a read operation is performed.
+     * These two bits are ignored by us and thrown away. Bits are "shifted in"
+     * by raising the input to the Management Data Clock (setting the MDC bit),
+     * and then reading the value of the MDIO bit.
+     */ 
+    ctrl = E1000_READ_REG(hw, CTRL);
+
+    /* Clear MDIO_DIR (SWDPIO1) to indicate this bit is to be used as input. */
+    ctrl &= ~E1000_CTRL_MDIO_DIR;
+    ctrl &= ~E1000_CTRL_MDIO;
+
+    E1000_WRITE_REG(hw, CTRL, ctrl);
+    E1000_WRITE_FLUSH(hw);
+
+    /* Raise and Lower the clock before reading in the data. This accounts for
+     * the turnaround bits. The first clock occurred when we clocked out the
+     * last bit of the Register Address.
+     */
+    e1000_raise_mdi_clk(hw, &ctrl);
+    e1000_lower_mdi_clk(hw, &ctrl);
+
+    for(data = 0, i = 0; i < 16; i++) {
+        data = data << 1;
+        e1000_raise_mdi_clk(hw, &ctrl);
+        ctrl = E1000_READ_REG(hw, CTRL);
+        /* Check to see if we shifted in a "1". */
+        if(ctrl & E1000_CTRL_MDIO) data |= 1;
+        e1000_lower_mdi_clk(hw, &ctrl);
+    }
+
+    e1000_raise_mdi_clk(hw, &ctrl);
+    e1000_lower_mdi_clk(hw, &ctrl);
+
+    return data;
+}
+
+/*****************************************************************************
+* Reads the value from a PHY register
+*
+* hw - Struct containing variables accessed by shared code
+* reg_addr - address of the PHY register to read
+******************************************************************************/
+int32_t
+e1000_read_phy_reg(struct e1000_hw *hw,
+                   uint32_t reg_addr,
+                   uint16_t *phy_data)
+{
+    uint32_t i;
+    uint32_t mdic = 0;
+    const uint32_t phy_addr = 1;
+
+    DEBUGFUNC("e1000_read_phy_reg");
+
+    if(reg_addr > MAX_PHY_REG_ADDRESS) {
+        DEBUGOUT1("PHY Address %d is out of range\n", reg_addr);
+        return -E1000_ERR_PARAM;
+    }
+
+    if(hw->mac_type > e1000_82543) {
+        /* Set up Op-code, Phy Address, and register address in the MDI
+         * Control register.  The MAC will take care of interfacing with the
+         * PHY to retrieve the desired data.
+         */
+        mdic = ((reg_addr << E1000_MDIC_REG_SHIFT) |
+                (phy_addr << E1000_MDIC_PHY_SHIFT) | 
+                (E1000_MDIC_OP_READ));
+
+        E1000_WRITE_REG(hw, MDIC, mdic);
+
+        /* Poll the ready bit to see if the MDI read completed */
+        for(i = 0; i < 64; i++) {
+            udelay(10);
+            mdic = E1000_READ_REG(hw, MDIC);
+            if(mdic & E1000_MDIC_READY) break;
+        }
+        if(!(mdic & E1000_MDIC_READY)) {
+            DEBUGOUT("MDI Read did not complete\n");
+            return -E1000_ERR_PHY;
+        }
+        if(mdic & E1000_MDIC_ERROR) {
+            DEBUGOUT("MDI Error\n");
+            return -E1000_ERR_PHY;
+        }
+        *phy_data = (uint16_t) mdic;
+    } else {
+        /* We must first send a preamble through the MDIO pin to signal the
+         * beginning of an MII instruction.  This is done by sending 32
+         * consecutive "1" bits.
+         */
+        e1000_shift_out_mdi_bits(hw, PHY_PREAMBLE, PHY_PREAMBLE_SIZE);
+
+        /* Now combine the next few fields that are required for a read
+         * operation.  We use this method instead of calling the
+         * e1000_shift_out_mdi_bits routine five different times. The format of
+         * a MII read instruction consists of a shift out of 14 bits and is
+         * defined as follows:
+         *    <Preamble><SOF><Op Code><Phy Addr><Reg Addr>
+         * followed by a shift in of 18 bits.  This first two bits shifted in
+         * are TurnAround bits used to avoid contention on the MDIO pin when a
+         * READ operation is performed.  These two bits are thrown away
+         * followed by a shift in of 16 bits which contains the desired data.
+         */
+        mdic = ((reg_addr) | (phy_addr << 5) | 
+                (PHY_OP_READ << 10) | (PHY_SOF << 12));
+
+        e1000_shift_out_mdi_bits(hw, mdic, 14);
+
+        /* Now that we've shifted out the read command to the MII, we need to
+         * "shift in" the 16-bit value (18 total bits) of the requested PHY
+         * register address.
+         */
+        *phy_data = e1000_shift_in_mdi_bits(hw);
+    }
+    return 0;
+}
+
+/******************************************************************************
+* Writes a value to a PHY register
+*
+* hw - Struct containing variables accessed by shared code
+* reg_addr - address of the PHY register to write
+* data - data to write to the PHY
+******************************************************************************/
+int32_t
+e1000_write_phy_reg(struct e1000_hw *hw,
+                    uint32_t reg_addr,
+                    uint16_t phy_data)
+{
+    uint32_t i;
+    uint32_t mdic = 0;
+    const uint32_t phy_addr = 1;
+
+    DEBUGFUNC("e1000_write_phy_reg");
+
+    if(reg_addr > MAX_PHY_REG_ADDRESS) {
+        DEBUGOUT1("PHY Address %d is out of range\n", reg_addr);
+        return -E1000_ERR_PARAM;
+    }
+
+    if(hw->mac_type > e1000_82543) {
+        /* Set up Op-code, Phy Address, register address, and data intended
+         * for the PHY register in the MDI Control register.  The MAC will take
+         * care of interfacing with the PHY to send the desired data.
+         */
+        mdic = (((uint32_t) phy_data) |
+                (reg_addr << E1000_MDIC_REG_SHIFT) |
+                (phy_addr << E1000_MDIC_PHY_SHIFT) | 
+                (E1000_MDIC_OP_WRITE));
+
+        E1000_WRITE_REG(hw, MDIC, mdic);
+
+        /* Poll the ready bit to see if the MDI read completed */
+        for(i = 0; i < 64; i++) {
+            udelay(10);
+            mdic = E1000_READ_REG(hw, MDIC);
+            if(mdic & E1000_MDIC_READY) break;
+        }
+        if(!(mdic & E1000_MDIC_READY)) {
+            DEBUGOUT("MDI Write did not complete\n");
+            return -E1000_ERR_PHY;
+        }
+    } else {
+        /* We'll need to use the SW defined pins to shift the write command
+         * out to the PHY. We first send a preamble to the PHY to signal the
+         * beginning of the MII instruction.  This is done by sending 32 
+         * consecutive "1" bits.
+         */
+        e1000_shift_out_mdi_bits(hw, PHY_PREAMBLE, PHY_PREAMBLE_SIZE);
+
+        /* Now combine the remaining required fields that will indicate a 
+         * write operation. We use this method instead of calling the
+         * e1000_shift_out_mdi_bits routine for each field in the command. The
+         * format of a MII write instruction is as follows:
+         * <Preamble><SOF><Op Code><Phy Addr><Reg Addr><Turnaround><Data>.
+         */
+        mdic = ((PHY_TURNAROUND) | (reg_addr << 2) | (phy_addr << 7) |
+                (PHY_OP_WRITE << 12) | (PHY_SOF << 14));
+        mdic <<= 16;
+        mdic |= (uint32_t) phy_data;
+
+        e1000_shift_out_mdi_bits(hw, mdic, 32);
+    }
+    return 0;
+}
+
+/******************************************************************************
+* Returns the PHY to the power-on reset state
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+void
+e1000_phy_hw_reset(struct e1000_hw *hw)
+{
+    uint32_t ctrl;
+    uint32_t ctrl_ext;
+
+    DEBUGFUNC("e1000_phy_hw_reset");
+
+    DEBUGOUT("Resetting Phy...\n");
+
+    if(hw->mac_type > e1000_82543) {
+        /* Read the device control register and assert the E1000_CTRL_PHY_RST
+         * bit. Then, take it out of reset.
+         */
+        ctrl = E1000_READ_REG(hw, CTRL);
+        E1000_WRITE_REG(hw, CTRL, ctrl | E1000_CTRL_PHY_RST);
+        E1000_WRITE_FLUSH(hw);
+        msec_delay(10);
+        E1000_WRITE_REG(hw, CTRL, ctrl);
+        E1000_WRITE_FLUSH(hw);
+    } else {
+        /* Read the Extended Device Control Register, assert the PHY_RESET_DIR
+         * bit to put the PHY into reset. Then, take it out of reset.
+         */
+        ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+        ctrl_ext |= E1000_CTRL_EXT_SDP4_DIR;
+        ctrl_ext &= ~E1000_CTRL_EXT_SDP4_DATA;
+        E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+        E1000_WRITE_FLUSH(hw);
+        msec_delay(10);
+        ctrl_ext |= E1000_CTRL_EXT_SDP4_DATA;
+        E1000_WRITE_REG(hw, CTRL_EXT, ctrl_ext);
+        E1000_WRITE_FLUSH(hw);
+    }
+    udelay(150);
+}
+
+/******************************************************************************
+* Resets the PHY
+*
+* hw - Struct containing variables accessed by shared code
+*
+* Sets bit 15 of the MII Control regiser
+******************************************************************************/
+int32_t
+e1000_phy_reset(struct e1000_hw *hw)
+{
+    uint16_t phy_data;
+
+    DEBUGFUNC("e1000_phy_reset");
+
+    if(e1000_read_phy_reg(hw, PHY_CTRL, &phy_data) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+    phy_data |= MII_CR_RESET;
+    if(e1000_write_phy_reg(hw, PHY_CTRL, phy_data) < 0) {
+        DEBUGOUT("PHY Write Error\n");
+        return -E1000_ERR_PHY;
+    }
+    udelay(1);
+    return 0;
+}
+
+/******************************************************************************
+* Probes the expected PHY address for known PHY IDs
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+int32_t
+e1000_detect_gig_phy(struct e1000_hw *hw)
+{
+    uint16_t phy_id_high, phy_id_low;
+    boolean_t match = FALSE;
+
+    DEBUGFUNC("e1000_detect_gig_phy");
+
+    /* Read the PHY ID Registers to identify which PHY is onboard. */
+    if(e1000_read_phy_reg(hw, PHY_ID1, &phy_id_high) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+    hw->phy_id = (uint32_t) (phy_id_high << 16);
+    udelay(2);
+    if(e1000_read_phy_reg(hw, PHY_ID2, &phy_id_low) < 0) {
+        DEBUGOUT("PHY Read Error\n");
+        return -E1000_ERR_PHY;
+    }
+    hw->phy_id |= (uint32_t) (phy_id_low & PHY_REVISION_MASK);
+    hw->phy_revision = (uint32_t) phy_id_low & ~PHY_REVISION_MASK;
+
+    switch(hw->mac_type) {
+    case e1000_82543:
+        if(hw->phy_id == M88E1000_E_PHY_ID) match = TRUE;
+        break;
+    case e1000_82544:
+        if(hw->phy_id == M88E1000_I_PHY_ID) match = TRUE;
+        break;
+    case e1000_82540:
+    case e1000_82545:
+    case e1000_82546:
+        if(hw->phy_id == M88E1011_I_PHY_ID) match = TRUE;
+        break;
+    default:
+        DEBUGOUT1("Invalid MAC type %d\n", hw->mac_type);
+        return -E1000_ERR_CONFIG;
+    }
+    if(match) {
+        DEBUGOUT1("PHY ID 0x%X detected\n", hw->phy_id);
+        return 0;
+    }
+    DEBUGOUT1("Invalid PHY ID 0x%X\n", hw->phy_id);
+    return -E1000_ERR_PHY;
+}
+
+/******************************************************************************
+* Resets the PHY's DSP
+*
+* hw - Struct containing variables accessed by shared code
+******************************************************************************/
+static int32_t
+e1000_phy_reset_dsp(struct e1000_hw *hw)
+{
+    int32_t ret_val = -E1000_ERR_PHY;
+    DEBUGFUNC("e1000_phy_reset_dsp");
+    
+    do {
+        if(e1000_write_phy_reg(hw, 29, 0x001d) < 0) break;
+        if(e1000_write_phy_reg(hw, 30, 0x00c1) < 0) break;
+        if(e1000_write_phy_reg(hw, 30, 0x0000) < 0) break;
+        ret_val = 0;
+    } while(0);
+
+    if(ret_val < 0) DEBUGOUT("PHY Write Error\n");
+    return ret_val;
+}
+
+/******************************************************************************
+* Get PHY information from various PHY registers
+*
+* hw - Struct containing variables accessed by shared code
+* phy_info - PHY information structure
+******************************************************************************/
+int32_t
+e1000_phy_get_info(struct e1000_hw *hw,
+                   struct e1000_phy_info *phy_info)
+{
+    int32_t ret_val = -E1000_ERR_PHY;
+    uint16_t phy_data;
+
+    DEBUGFUNC("e1000_phy_get_info");
+
+    phy_info->cable_length = e1000_cable_length_undefined;
+    phy_info->extended_10bt_distance = e1000_10bt_ext_dist_enable_undefined;
+    phy_info->cable_polarity = e1000_rev_polarity_undefined;
+    phy_info->polarity_correction = e1000_polarity_reversal_undefined;
+    phy_info->mdix_mode = e1000_auto_x_mode_undefined;
+    phy_info->local_rx = e1000_1000t_rx_status_undefined;
+    phy_info->remote_rx = e1000_1000t_rx_status_undefined;
+
+    if(hw->media_type != e1000_media_type_copper) {
+        DEBUGOUT("PHY info is only valid for copper media\n");
+        return -E1000_ERR_CONFIG;
+    }
+
+    do {
+        if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) break;
+        if(e1000_read_phy_reg(hw, PHY_STATUS, &phy_data) < 0) break;
+        if((phy_data & MII_SR_LINK_STATUS) != MII_SR_LINK_STATUS) {
+            DEBUGOUT("PHY info is only valid if link is up\n");
+            return -E1000_ERR_CONFIG;
+        }
+
+        if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data) < 0)
+            break;
+        phy_info->extended_10bt_distance =
+            (phy_data & M88E1000_PSCR_10BT_EXT_DIST_ENABLE) >>
+            M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT;
+        phy_info->polarity_correction =
+            (phy_data & M88E1000_PSCR_POLARITY_REVERSAL) >>
+            M88E1000_PSCR_POLARITY_REVERSAL_SHIFT;
+
+        if(e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data) < 0)
+            break;
+        phy_info->cable_polarity = (phy_data & M88E1000_PSSR_REV_POLARITY) >>
+            M88E1000_PSSR_REV_POLARITY_SHIFT;
+        phy_info->mdix_mode = (phy_data & M88E1000_PSSR_MDIX) >>
+            M88E1000_PSSR_MDIX_SHIFT;
+        if(phy_data & M88E1000_PSSR_1000MBS) {
+            /* Cable Length Estimation and Local/Remote Receiver Informatoion
+             * are only valid at 1000 Mbps
+             */
+            phy_info->cable_length = ((phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
+                                      M88E1000_PSSR_CABLE_LENGTH_SHIFT);
+            if(e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data) < 0) 
+                break;
+            phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >>
+                SR_1000T_LOCAL_RX_STATUS_SHIFT;
+            phy_info->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) >>
+                SR_1000T_REMOTE_RX_STATUS_SHIFT;
+        }
+        ret_val = 0;
+    } while(0);
+
+    if(ret_val < 0) DEBUGOUT("PHY Read Error\n");
+    return ret_val;
+}
+
+int32_t
+e1000_validate_mdi_setting(struct e1000_hw *hw)
+{
+    DEBUGFUNC("e1000_validate_mdi_settings");
+
+    if(!hw->autoneg && (hw->mdix == 0 || hw->mdix == 3)) {
+        DEBUGOUT("Invalid MDI setting detected\n");
+        hw->mdix = 1;
+        return -E1000_ERR_CONFIG;
+    }
+    return 0;
+}
+
+/******************************************************************************
+ * Raises the EEPROM's clock input.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * eecd - EECD's current value
+ *****************************************************************************/
+static void
+e1000_raise_ee_clk(struct e1000_hw *hw,
+                   uint32_t *eecd)
+{
+    /* Raise the clock input to the EEPROM (by setting the SK bit), and then
+     * wait <delay> microseconds.
+     */
+    *eecd = *eecd | E1000_EECD_SK;
+    E1000_WRITE_REG(hw, EECD, *eecd);
+    E1000_WRITE_FLUSH(hw);
+    udelay(50);
+}
+
+/******************************************************************************
+ * Lowers the EEPROM's clock input.
+ *
+ * hw - Struct containing variables accessed by shared code 
+ * eecd - EECD's current value
+ *****************************************************************************/
+static void
+e1000_lower_ee_clk(struct e1000_hw *hw,
+                   uint32_t *eecd)
+{
+    /* Lower the clock input to the EEPROM (by clearing the SK bit), and then 
+     * wait 50 microseconds. 
+     */
+    *eecd = *eecd & ~E1000_EECD_SK;
+    E1000_WRITE_REG(hw, EECD, *eecd);
+    E1000_WRITE_FLUSH(hw);
+    udelay(50);
+}
+
+/******************************************************************************
+ * Shift data bits out to the EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * data - data to send to the EEPROM
+ * count - number of bits to shift out
+ *****************************************************************************/
+static void
+e1000_shift_out_ee_bits(struct e1000_hw *hw,
+                        uint16_t data,
+                        uint16_t count)
+{
+    uint32_t eecd;
+    uint32_t mask;
+
+    /* We need to shift "count" bits out to the EEPROM. So, value in the
+     * "data" parameter will be shifted out to the EEPROM one bit at a time.
+     * In order to do this, "data" must be broken down into bits. 
+     */
+    mask = 0x01 << (count - 1);
+    eecd = E1000_READ_REG(hw, EECD);
+    eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
+    do {
+        /* A "1" is shifted out to the EEPROM by setting bit "DI" to a "1",
+         * and then raising and then lowering the clock (the SK bit controls
+         * the clock input to the EEPROM).  A "0" is shifted out to the EEPROM
+         * by setting "DI" to "0" and then raising and then lowering the clock.
+         */
+        eecd &= ~E1000_EECD_DI;
+
+        if(data & mask)
+            eecd |= E1000_EECD_DI;
+
+        E1000_WRITE_REG(hw, EECD, eecd);
+        E1000_WRITE_FLUSH(hw);
+
+        udelay(50);
+
+        e1000_raise_ee_clk(hw, &eecd);
+        e1000_lower_ee_clk(hw, &eecd);
+
+        mask = mask >> 1;
+
+    } while(mask);
+
+    /* We leave the "DI" bit set to "0" when we leave this routine. */
+    eecd &= ~E1000_EECD_DI;
+    E1000_WRITE_REG(hw, EECD, eecd);
+}
+
+/******************************************************************************
+ * Shift data bits in from the EEPROM
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static uint16_t
+e1000_shift_in_ee_bits(struct e1000_hw *hw)
+{
+    uint32_t eecd;
+    uint32_t i;
+    uint16_t data;
+
+    /* In order to read a register from the EEPROM, we need to shift 'count'
+     * bits in from the EEPROM. Bits are "shifted in" by raising the clock
+     * input to the EEPROM (setting the SK bit), and then reading the value of
+     * the "DO" bit.  During this "shifting in" process the "DI" bit should
+     * always be clear.
+     */
+
+    eecd = E1000_READ_REG(hw, EECD);
+
+    eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
+    data = 0;
+
+    for(i = 0; i < 16; i++) {
+        data = data << 1;
+        e1000_raise_ee_clk(hw, &eecd);
+
+        eecd = E1000_READ_REG(hw, EECD);
+
+        eecd &= ~(E1000_EECD_DI);
+        if(eecd & E1000_EECD_DO)
+            data |= 1;
+
+        e1000_lower_ee_clk(hw, &eecd);
+    }
+
+    return data;
+}
+
+/******************************************************************************
+ * Prepares EEPROM for access
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Lowers EEPROM clock. Clears input pin. Sets the chip select pin. This 
+ * function should be called before issuing a command to the EEPROM.
+ *****************************************************************************/
+static void
+e1000_setup_eeprom(struct e1000_hw *hw)
+{
+    uint32_t eecd;
+
+    eecd = E1000_READ_REG(hw, EECD);
+
+    /* Clear SK and DI */
+    eecd &= ~(E1000_EECD_SK | E1000_EECD_DI);
+    E1000_WRITE_REG(hw, EECD, eecd);
+
+    /* Set CS */
+    eecd |= E1000_EECD_CS;
+    E1000_WRITE_REG(hw, EECD, eecd);
+}
+
+/******************************************************************************
+ * Returns EEPROM to a "standby" state
+ * 
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static void
+e1000_standby_eeprom(struct e1000_hw *hw)
+{
+    uint32_t eecd;
+
+    eecd = E1000_READ_REG(hw, EECD);
+
+    /* Deselct EEPROM */
+    eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+    E1000_WRITE_REG(hw, EECD, eecd);
+    E1000_WRITE_FLUSH(hw);
+    udelay(50);
+
+    /* Clock high */
+    eecd |= E1000_EECD_SK;
+    E1000_WRITE_REG(hw, EECD, eecd);
+    E1000_WRITE_FLUSH(hw);
+    udelay(50);
+
+    /* Select EEPROM */
+    eecd |= E1000_EECD_CS;
+    E1000_WRITE_REG(hw, EECD, eecd);
+    E1000_WRITE_FLUSH(hw);
+    udelay(50);
+
+    /* Clock low */
+    eecd &= ~E1000_EECD_SK;
+    E1000_WRITE_REG(hw, EECD, eecd);
+    E1000_WRITE_FLUSH(hw);
+    udelay(50);
+}
+
+/******************************************************************************
+ * Raises then lowers the EEPROM's clock pin
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static void
+e1000_clock_eeprom(struct e1000_hw *hw)
+{
+    uint32_t eecd;
+
+    eecd = E1000_READ_REG(hw, EECD);
+
+    /* Rising edge of clock */
+    eecd |= E1000_EECD_SK;
+    E1000_WRITE_REG(hw, EECD, eecd);
+    E1000_WRITE_FLUSH(hw);
+    udelay(50);
+
+    /* Falling edge of clock */
+    eecd &= ~E1000_EECD_SK;
+    E1000_WRITE_REG(hw, EECD, eecd);
+    E1000_WRITE_FLUSH(hw);
+    udelay(50);
+}
+
+/******************************************************************************
+ * Terminates a command by lowering the EEPROM's chip select pin
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+static void
+e1000_cleanup_eeprom(struct e1000_hw *hw)
+{
+    uint32_t eecd;
+
+    eecd = E1000_READ_REG(hw, EECD);
+
+    eecd &= ~(E1000_EECD_CS | E1000_EECD_DI);
+
+    E1000_WRITE_REG(hw, EECD, eecd);
+
+    e1000_clock_eeprom(hw);
+}
+
+/******************************************************************************
+ * Reads a 16 bit word from the EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset of  word in the EEPROM to read
+ * data - word read from the EEPROM 
+ *****************************************************************************/
+int32_t
+e1000_read_eeprom(struct e1000_hw *hw,
+                  uint16_t offset,
+                  uint16_t *data)
+{
+    uint32_t eecd;
+    uint32_t i = 0;
+    boolean_t large_eeprom = FALSE;
+
+    DEBUGFUNC("e1000_read_eeprom");
+
+    /* Request EEPROM Access */
+    if(hw->mac_type > e1000_82544) {
+        eecd = E1000_READ_REG(hw, EECD);
+        if(eecd & E1000_EECD_SIZE) large_eeprom = TRUE;
+        eecd |= E1000_EECD_REQ;
+        E1000_WRITE_REG(hw, EECD, eecd);
+        eecd = E1000_READ_REG(hw, EECD);
+        while((!(eecd & E1000_EECD_GNT)) && (i < 100)) {
+            i++;
+            udelay(5);
+            eecd = E1000_READ_REG(hw, EECD);
+        }
+        if(!(eecd & E1000_EECD_GNT)) {
+            eecd &= ~E1000_EECD_REQ;
+            E1000_WRITE_REG(hw, EECD, eecd);
+            DEBUGOUT("Could not acquire EEPROM grant\n");
+            return -E1000_ERR_EEPROM;
+        }
+    }
+
+    /*  Prepare the EEPROM for reading  */
+    e1000_setup_eeprom(hw);
+
+    /*  Send the READ command (opcode + addr)  */
+    e1000_shift_out_ee_bits(hw, EEPROM_READ_OPCODE, 3);
+    if(large_eeprom) {
+        /* If we have a 256 word EEPROM, there are 8 address bits */
+        e1000_shift_out_ee_bits(hw, offset, 8);
+    } else {
+        /* If we have a 64 word EEPROM, there are 6 address bits */
+        e1000_shift_out_ee_bits(hw, offset, 6);
+    }
+
+    /* Read the data */
+    *data = e1000_shift_in_ee_bits(hw);
+
+    /* End this read operation */
+    e1000_standby_eeprom(hw);
+
+    /* Stop requesting EEPROM access */
+    if(hw->mac_type > e1000_82544) {
+        eecd = E1000_READ_REG(hw, EECD);
+        eecd &= ~E1000_EECD_REQ;
+        E1000_WRITE_REG(hw, EECD, eecd);
+    }
+
+    return 0;
+}
+
+/******************************************************************************
+ * Verifies that the EEPROM has a valid checksum
+ * 
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Reads the first 64 16 bit words of the EEPROM and sums the values read.
+ * If the the sum of the 64 16 bit words is 0xBABA, the EEPROM's checksum is
+ * valid.
+ *****************************************************************************/
+int32_t
+e1000_validate_eeprom_checksum(struct e1000_hw *hw)
+{
+    uint16_t checksum = 0;
+    uint16_t i, eeprom_data;
+
+    DEBUGFUNC("e1000_validate_eeprom_checksum");
+
+    for(i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) {
+        if(e1000_read_eeprom(hw, i, &eeprom_data) < 0) {
+            DEBUGOUT("EEPROM Read Error\n");
+            return -E1000_ERR_EEPROM;
+        }
+        checksum += eeprom_data;
+    }
+
+    if(checksum == (uint16_t) EEPROM_SUM) {
+        return 0;
+    } else {
+        DEBUGOUT("EEPROM Checksum Invalid\n");    
+        return -E1000_ERR_EEPROM;
+    }
+}
+
+/******************************************************************************
+ * Calculates the EEPROM checksum and writes it to the EEPROM
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Sums the first 63 16 bit words of the EEPROM. Subtracts the sum from 0xBABA.
+ * Writes the difference to word offset 63 of the EEPROM.
+ *****************************************************************************/
+int32_t
+e1000_update_eeprom_checksum(struct e1000_hw *hw)
+{
+    uint16_t checksum = 0;
+    uint16_t i, eeprom_data;
+
+    DEBUGFUNC("e1000_update_eeprom_checksum");
+
+    for(i = 0; i < EEPROM_CHECKSUM_REG; i++) {
+        if(e1000_read_eeprom(hw, i, &eeprom_data) < 0) {
+            DEBUGOUT("EEPROM Read Error\n");
+            return -E1000_ERR_EEPROM;
+        }
+        checksum += eeprom_data;
+    }
+    checksum = (uint16_t) EEPROM_SUM - checksum;
+    if(e1000_write_eeprom(hw, EEPROM_CHECKSUM_REG, checksum) < 0) {
+        DEBUGOUT("EEPROM Write Error\n");
+        return -E1000_ERR_EEPROM;
+    }
+    return 0;
+}
+
+/******************************************************************************
+ * Writes a 16 bit word to a given offset in the EEPROM.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset within the EEPROM to be written to
+ * data - 16 bit word to be writen to the EEPROM
+ *
+ * If e1000_update_eeprom_checksum is not called after this function, the 
+ * EEPROM will most likely contain an invalid checksum.
+ *****************************************************************************/
+int32_t
+e1000_write_eeprom(struct e1000_hw *hw,
+                   uint16_t offset,
+                   uint16_t data)
+{
+    uint32_t eecd;
+    uint32_t i = 0;
+    int32_t status = 0;
+    boolean_t large_eeprom = FALSE;
+
+    DEBUGFUNC("e1000_write_eeprom");
+
+    /* Request EEPROM Access */
+    if(hw->mac_type > e1000_82544) {
+        eecd = E1000_READ_REG(hw, EECD);
+        if(eecd & E1000_EECD_SIZE) large_eeprom = TRUE;
+        eecd |= E1000_EECD_REQ;
+        E1000_WRITE_REG(hw, EECD, eecd);
+        eecd = E1000_READ_REG(hw, EECD);
+        while((!(eecd & E1000_EECD_GNT)) && (i < 100)) {
+            i++;
+            udelay(5);
+            eecd = E1000_READ_REG(hw, EECD);
+        }
+        if(!(eecd & E1000_EECD_GNT)) {
+            eecd &= ~E1000_EECD_REQ;
+            E1000_WRITE_REG(hw, EECD, eecd);
+            DEBUGOUT("Could not acquire EEPROM grant\n");
+            return -E1000_ERR_EEPROM;
+        }
+    }
+
+    /* Prepare the EEPROM for writing  */
+    e1000_setup_eeprom(hw);
+
+    /* Send the 9-bit (or 11-bit on large EEPROM) EWEN (write enable) command
+     * to the EEPROM (5-bit opcode plus 4/6-bit dummy). This puts the EEPROM
+     * into write/erase mode. 
+     */
+    e1000_shift_out_ee_bits(hw, EEPROM_EWEN_OPCODE, 5);
+    if(large_eeprom) 
+        e1000_shift_out_ee_bits(hw, 0, 6);
+    else
+        e1000_shift_out_ee_bits(hw, 0, 4);
+
+    /* Prepare the EEPROM */
+    e1000_standby_eeprom(hw);
+
+    /* Send the Write command (3-bit opcode + addr) */
+    e1000_shift_out_ee_bits(hw, EEPROM_WRITE_OPCODE, 3);
+    if(large_eeprom) 
+        /* If we have a 256 word EEPROM, there are 8 address bits */
+        e1000_shift_out_ee_bits(hw, offset, 8);
+    else
+        /* If we have a 64 word EEPROM, there are 6 address bits */
+        e1000_shift_out_ee_bits(hw, offset, 6);
+
+    /* Send the data */
+    e1000_shift_out_ee_bits(hw, data, 16);
+
+    /* Toggle the CS line.  This in effect tells to EEPROM to actually execute 
+     * the command in question.
+     */
+    e1000_standby_eeprom(hw);
+
+    /* Now read DO repeatedly until is high (equal to '1').  The EEEPROM will
+     * signal that the command has been completed by raising the DO signal.
+     * If DO does not go high in 10 milliseconds, then error out.
+     */
+    for(i = 0; i < 200; i++) {
+        eecd = E1000_READ_REG(hw, EECD);
+        if(eecd & E1000_EECD_DO) break;
+        udelay(50);
+    }
+    if(i == 200) {
+        DEBUGOUT("EEPROM Write did not complete\n");
+        status = -E1000_ERR_EEPROM;
+    }
+
+    /* Recover from write */
+    e1000_standby_eeprom(hw);
+
+    /* Send the 9-bit (or 11-bit on large EEPROM) EWDS (write disable) command
+     * to the EEPROM (5-bit opcode plus 4/6-bit dummy). This takes the EEPROM
+     * out of write/erase mode.
+     */
+    e1000_shift_out_ee_bits(hw, EEPROM_EWDS_OPCODE, 5);
+    if(large_eeprom) 
+        e1000_shift_out_ee_bits(hw, 0, 6);
+    else
+        e1000_shift_out_ee_bits(hw, 0, 4);
+
+    /* Done with writing */
+    e1000_cleanup_eeprom(hw);
+
+    /* Stop requesting EEPROM access */
+    if(hw->mac_type > e1000_82544) {
+        eecd = E1000_READ_REG(hw, EECD);
+        eecd &= ~E1000_EECD_REQ;
+        E1000_WRITE_REG(hw, EECD, eecd);
+    }
+
+    return status;
+}
+
+/******************************************************************************
+ * Reads the adapter's part number from the EEPROM
+ *
+ * hw - Struct containing variables accessed by shared code
+ * part_num - Adapter's part number
+ *****************************************************************************/
+int32_t
+e1000_read_part_num(struct e1000_hw *hw,
+                    uint32_t *part_num)
+{
+    uint16_t offset = EEPROM_PBA_BYTE_1;
+    uint16_t eeprom_data;
+
+    DEBUGFUNC("e1000_read_part_num");
+
+    /* Get word 0 from EEPROM */
+    if(e1000_read_eeprom(hw, offset, &eeprom_data) < 0) {
+        DEBUGOUT("EEPROM Read Error\n");
+        return -E1000_ERR_EEPROM;
+    }
+    /* Save word 0 in upper half of part_num */
+    *part_num = (uint32_t) (eeprom_data << 16);
+
+    /* Get word 1 from EEPROM */
+    if(e1000_read_eeprom(hw, ++offset, &eeprom_data) < 0) {
+        DEBUGOUT("EEPROM Read Error\n");
+        return -E1000_ERR_EEPROM;
+    }
+    /* Save word 1 in lower half of part_num */
+    *part_num |= eeprom_data;
+
+    return 0;
+}
+
+/******************************************************************************
+ * Reads the adapter's MAC address from the EEPROM and inverts the LSB for the
+ * second function of dual function devices
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+e1000_read_mac_addr(struct e1000_hw * hw)
+{
+    uint16_t offset;
+    uint16_t eeprom_data, i;
+
+    DEBUGFUNC("e1000_read_mac_addr");
+
+    for(i = 0; i < NODE_ADDRESS_SIZE; i += 2) {
+        offset = i >> 1;
+        if(e1000_read_eeprom(hw, offset, &eeprom_data) < 0) {
+            DEBUGOUT("EEPROM Read Error\n");
+            return -E1000_ERR_EEPROM;
+        }
+        hw->perm_mac_addr[i] = (uint8_t) (eeprom_data & 0x00FF);
+        hw->perm_mac_addr[i+1] = (uint8_t) (eeprom_data >> 8);
+    }
+    if((hw->mac_type == e1000_82546) &&
+       (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) {
+        if(hw->perm_mac_addr[5] & 0x01)
+            hw->perm_mac_addr[5] &= ~(0x01);
+        else
+            hw->perm_mac_addr[5] |= 0x01;
+    }
+    for(i = 0; i < NODE_ADDRESS_SIZE; i++)
+        hw->mac_addr[i] = hw->perm_mac_addr[i];
+    return 0;
+}
+
+/******************************************************************************
+ * Initializes receive address filters.
+ *
+ * hw - Struct containing variables accessed by shared code 
+ *
+ * Places the MAC address in receive address register 0 and clears the rest
+ * of the receive addresss registers. Clears the multicast table. Assumes
+ * the receiver is in reset when the routine is called.
+ *****************************************************************************/
+void
+e1000_init_rx_addrs(struct e1000_hw *hw)
+{
+    uint32_t i;
+    uint32_t addr_low;
+    uint32_t addr_high;
+
+    DEBUGFUNC("e1000_init_rx_addrs");
+
+    /* Setup the receive address. */
+    DEBUGOUT("Programming MAC Address into RAR[0]\n");
+    addr_low = (hw->mac_addr[0] |
+                (hw->mac_addr[1] << 8) |
+                (hw->mac_addr[2] << 16) | (hw->mac_addr[3] << 24));
+
+    addr_high = (hw->mac_addr[4] |
+                 (hw->mac_addr[5] << 8) | E1000_RAH_AV);
+
+    E1000_WRITE_REG_ARRAY(hw, RA, 0, addr_low);
+    E1000_WRITE_REG_ARRAY(hw, RA, 1, addr_high);
+
+    /* Zero out the other 15 receive addresses. */
+    DEBUGOUT("Clearing RAR[1-15]\n");
+    for(i = 1; i < E1000_RAR_ENTRIES; i++) {
+        E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0);
+        E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0);
+    }
+}
+
+/******************************************************************************
+ * Updates the MAC's list of multicast addresses.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * mc_addr_list - the list of new multicast addresses
+ * mc_addr_count - number of addresses
+ * pad - number of bytes between addresses in the list
+ *
+ * The given list replaces any existing list. Clears the last 15 receive
+ * address registers and the multicast table. Uses receive address registers
+ * for the first 15 multicast addresses, and hashes the rest into the 
+ * multicast table.
+ *****************************************************************************/
+void
+e1000_mc_addr_list_update(struct e1000_hw *hw,
+                          uint8_t *mc_addr_list,
+                          uint32_t mc_addr_count,
+                          uint32_t pad)
+{
+    uint32_t hash_value;
+    uint32_t i;
+    uint32_t rar_used_count = 1; /* RAR[0] is used for our MAC address */
+
+    DEBUGFUNC("e1000_mc_addr_list_update");
+
+    /* Set the new number of MC addresses that we are being requested to use. */
+    hw->num_mc_addrs = mc_addr_count;
+
+    /* Clear RAR[1-15] */
+    DEBUGOUT(" Clearing RAR[1-15]\n");
+    for(i = rar_used_count; i < E1000_RAR_ENTRIES; i++) {
+        E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0);
+        E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0);
+    }
+
+    /* Clear the MTA */
+    DEBUGOUT(" Clearing MTA\n");
+    for(i = 0; i < E1000_NUM_MTA_REGISTERS; i++) {
+        E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
+    }
+
+    /* Add the new addresses */
+    for(i = 0; i < mc_addr_count; i++) {
+        DEBUGOUT(" Adding the multicast addresses:\n");
+        DEBUGOUT7(" MC Addr #%d =%.2X %.2X %.2X %.2X %.2X %.2X\n", i,
+                  mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad)],
+                  mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 1],
+                  mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 2],
+                  mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 3],
+                  mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 4],
+                  mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 5]);
+
+        hash_value = e1000_hash_mc_addr(hw,
+                                        mc_addr_list +
+                                        (i * (ETH_LENGTH_OF_ADDRESS + pad)));
+
+        DEBUGOUT1(" Hash value = 0x%03X\n", hash_value);
+
+        /* Place this multicast address in the RAR if there is room, *
+         * else put it in the MTA            
+         */
+        if(rar_used_count < E1000_RAR_ENTRIES) {
+            e1000_rar_set(hw,
+                          mc_addr_list + (i * (ETH_LENGTH_OF_ADDRESS + pad)),
+                          rar_used_count);
+            rar_used_count++;
+        } else {
+            e1000_mta_set(hw, hash_value);
+        }
+    }
+    DEBUGOUT("MC Update Complete\n");
+}
+
+/******************************************************************************
+ * Hashes an address to determine its location in the multicast table
+ *
+ * hw - Struct containing variables accessed by shared code
+ * mc_addr - the multicast address to hash 
+ *****************************************************************************/
+uint32_t
+e1000_hash_mc_addr(struct e1000_hw *hw,
+                   uint8_t *mc_addr)
+{
+    uint32_t hash_value = 0;
+
+    /* The portion of the address that is used for the hash table is
+     * determined by the mc_filter_type setting.  
+     */
+    switch (hw->mc_filter_type) {
+    /* [0] [1] [2] [3] [4] [5]
+     * 01  AA  00  12  34  56
+     * LSB                 MSB
+     */
+    case 0:
+        /* [47:36] i.e. 0x563 for above example address */
+        hash_value = ((mc_addr[4] >> 4) | (((uint16_t) mc_addr[5]) << 4));
+        break;
+    case 1:
+        /* [46:35] i.e. 0xAC6 for above example address */
+        hash_value = ((mc_addr[4] >> 3) | (((uint16_t) mc_addr[5]) << 5));
+        break;
+    case 2:
+        /* [45:34] i.e. 0x5D8 for above example address */
+        hash_value = ((mc_addr[4] >> 2) | (((uint16_t) mc_addr[5]) << 6));
+        break;
+    case 3:
+        /* [43:32] i.e. 0x634 for above example address */
+        hash_value = ((mc_addr[4]) | (((uint16_t) mc_addr[5]) << 8));
+        break;
+    }
+
+    hash_value &= 0xFFF;
+    return hash_value;
+}
+
+/******************************************************************************
+ * Sets the bit in the multicast table corresponding to the hash value.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * hash_value - Multicast address hash value
+ *****************************************************************************/
+void
+e1000_mta_set(struct e1000_hw *hw,
+              uint32_t hash_value)
+{
+    uint32_t hash_bit, hash_reg;
+    uint32_t mta;
+    uint32_t temp;
+
+    /* The MTA is a register array of 128 32-bit registers.  
+     * It is treated like an array of 4096 bits.  We want to set 
+     * bit BitArray[hash_value]. So we figure out what register
+     * the bit is in, read it, OR in the new bit, then write
+     * back the new value.  The register is determined by the 
+     * upper 7 bits of the hash value and the bit within that 
+     * register are determined by the lower 5 bits of the value.
+     */
+    hash_reg = (hash_value >> 5) & 0x7F;
+    hash_bit = hash_value & 0x1F;
+
+    mta = E1000_READ_REG_ARRAY(hw, MTA, hash_reg);
+
+    mta |= (1 << hash_bit);
+
+    /* If we are on an 82544 and we are trying to write an odd offset
+     * in the MTA, save off the previous entry before writing and
+     * restore the old value after writing.
+     */
+    if((hw->mac_type == e1000_82544) && ((hash_reg & 0x1) == 1)) {
+        temp = E1000_READ_REG_ARRAY(hw, MTA, (hash_reg - 1));
+        E1000_WRITE_REG_ARRAY(hw, MTA, hash_reg, mta);
+        E1000_WRITE_REG_ARRAY(hw, MTA, (hash_reg - 1), temp);
+    } else {
+        E1000_WRITE_REG_ARRAY(hw, MTA, hash_reg, mta);
+    }
+}
+
+/******************************************************************************
+ * Puts an ethernet address into a receive address register.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * addr - Address to put into receive address register
+ * index - Receive address register to write
+ *****************************************************************************/
+void
+e1000_rar_set(struct e1000_hw *hw,
+              uint8_t *addr,
+              uint32_t index)
+{
+    uint32_t rar_low, rar_high;
+
+    /* HW expects these in little endian so we reverse the byte order
+     * from network order (big endian) to little endian              
+     */
+    rar_low = ((uint32_t) addr[0] |
+               ((uint32_t) addr[1] << 8) |
+               ((uint32_t) addr[2] << 16) | ((uint32_t) addr[3] << 24));
+
+    rar_high = ((uint32_t) addr[4] | ((uint32_t) addr[5] << 8) | E1000_RAH_AV);
+
+    E1000_WRITE_REG_ARRAY(hw, RA, (index << 1), rar_low);
+    E1000_WRITE_REG_ARRAY(hw, RA, ((index << 1) + 1), rar_high);
+}
+
+/******************************************************************************
+ * Writes a value to the specified offset in the VLAN filter table.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - Offset in VLAN filer table to write
+ * value - Value to write into VLAN filter table
+ *****************************************************************************/
+void
+e1000_write_vfta(struct e1000_hw *hw,
+                 uint32_t offset,
+                 uint32_t value)
+{
+    uint32_t temp;
+
+    if((hw->mac_type == e1000_82544) && ((offset & 0x1) == 1)) {
+        temp = E1000_READ_REG_ARRAY(hw, VFTA, (offset - 1));
+        E1000_WRITE_REG_ARRAY(hw, VFTA, offset, value);
+        E1000_WRITE_REG_ARRAY(hw, VFTA, (offset - 1), temp);
+    } else {
+        E1000_WRITE_REG_ARRAY(hw, VFTA, offset, value);
+    }
+}
+
+/******************************************************************************
+ * Clears the VLAN filer table
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+void
+e1000_clear_vfta(struct e1000_hw *hw)
+{
+    uint32_t offset;
+
+    for(offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++)
+        E1000_WRITE_REG_ARRAY(hw, VFTA, offset, 0);
+}
+
+static int32_t
+e1000_id_led_init(struct e1000_hw * hw)
+{
+    uint32_t ledctl;
+    const uint32_t ledctl_mask = 0x000000FF;
+    const uint32_t ledctl_on = E1000_LEDCTL_MODE_LED_ON;
+    const uint32_t ledctl_off = E1000_LEDCTL_MODE_LED_OFF;
+    uint16_t eeprom_data, i, temp;
+    const uint16_t led_mask = 0x0F;
+        
+    DEBUGFUNC("e1000_id_led_init");
+    
+    if(hw->mac_type < e1000_82540) {
+        /* Nothing to do */
+        return 0;
+    }
+    
+    ledctl = E1000_READ_REG(hw, LEDCTL);
+    hw->ledctl_default = ledctl;
+    hw->ledctl_mode1 = hw->ledctl_default;
+    hw->ledctl_mode2 = hw->ledctl_default;
+        
+    if(e1000_read_eeprom(hw, EEPROM_ID_LED_SETTINGS, &eeprom_data) < 0) {
+        DEBUGOUT("EEPROM Read Error\n");
+        return -E1000_ERR_EEPROM;
+    }
+    if((eeprom_data== ID_LED_RESERVED_0000) || 
+       (eeprom_data == ID_LED_RESERVED_FFFF)) eeprom_data = ID_LED_DEFAULT;
+    for(i = 0; i < 4; i++) {
+        temp = (eeprom_data >> (i << 2)) & led_mask;
+        switch(temp) {
+        case ID_LED_ON1_DEF2:
+        case ID_LED_ON1_ON2:
+        case ID_LED_ON1_OFF2:
+            hw->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
+            hw->ledctl_mode1 |= ledctl_on << (i << 3);
+            break;
+        case ID_LED_OFF1_DEF2:
+        case ID_LED_OFF1_ON2:
+        case ID_LED_OFF1_OFF2:
+            hw->ledctl_mode1 &= ~(ledctl_mask << (i << 3));
+            hw->ledctl_mode1 |= ledctl_off << (i << 3);
+            break;
+        default:
+            /* Do nothing */
+            break;
+        }
+        switch(temp) {
+        case ID_LED_DEF1_ON2:
+        case ID_LED_ON1_ON2:
+        case ID_LED_OFF1_ON2:
+            hw->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
+            hw->ledctl_mode2 |= ledctl_on << (i << 3);
+            break;
+        case ID_LED_DEF1_OFF2:
+        case ID_LED_ON1_OFF2:
+        case ID_LED_OFF1_OFF2:
+            hw->ledctl_mode2 &= ~(ledctl_mask << (i << 3));
+            hw->ledctl_mode2 |= ledctl_off << (i << 3);
+            break;
+        default:
+            /* Do nothing */
+            break;
+        }
+    }
+    return 0;
+}
+
+/******************************************************************************
+ * Prepares SW controlable LED for use and saves the current state of the LED.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+e1000_setup_led(struct e1000_hw *hw)
+{
+    uint32_t ledctl;
+    DEBUGFUNC("e1000_setup_led");
+   
+    switch(hw->device_id) {
+    case E1000_DEV_ID_82542:
+    case E1000_DEV_ID_82543GC_FIBER:
+    case E1000_DEV_ID_82543GC_COPPER:
+    case E1000_DEV_ID_82544EI_COPPER:
+    case E1000_DEV_ID_82544EI_FIBER:
+    case E1000_DEV_ID_82544GC_COPPER:
+    case E1000_DEV_ID_82544GC_LOM:
+        /* No setup necessary */
+        break;
+    case E1000_DEV_ID_82545EM_FIBER:
+    case E1000_DEV_ID_82546EB_FIBER:
+        ledctl = E1000_READ_REG(hw, LEDCTL);
+        /* Save current LEDCTL settings */
+        hw->ledctl_default = ledctl;
+        /* Turn off LED0 */
+        ledctl &= ~(E1000_LEDCTL_LED0_IVRT |
+                    E1000_LEDCTL_LED0_BLINK | 
+                    E1000_LEDCTL_LED0_MODE_MASK);
+        ledctl |= (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED0_MODE_SHIFT);
+        E1000_WRITE_REG(hw, LEDCTL, ledctl);
+        break;
+    case E1000_DEV_ID_82540EP:
+    case E1000_DEV_ID_82540EP_LOM:
+    case E1000_DEV_ID_82540EP_LP:
+    case E1000_DEV_ID_82540EM:
+    case E1000_DEV_ID_82540EM_LOM:
+    case E1000_DEV_ID_82545EM_COPPER:
+    case E1000_DEV_ID_82546EB_COPPER:
+        E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1);
+        break;
+    default:
+        DEBUGOUT("Invalid device ID\n");
+        return -E1000_ERR_CONFIG;
+    }
+    return 0;
+}
+
+/******************************************************************************
+ * Restores the saved state of the SW controlable LED.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+e1000_cleanup_led(struct e1000_hw *hw)
+{
+    DEBUGFUNC("e1000_cleanup_led");
+
+    switch(hw->device_id) {
+    case E1000_DEV_ID_82542:
+    case E1000_DEV_ID_82543GC_FIBER:
+    case E1000_DEV_ID_82543GC_COPPER:
+    case E1000_DEV_ID_82544EI_COPPER:
+    case E1000_DEV_ID_82544EI_FIBER:
+    case E1000_DEV_ID_82544GC_COPPER:
+    case E1000_DEV_ID_82544GC_LOM:
+        /* No cleanup necessary */
+        break;
+    case E1000_DEV_ID_82540EP:
+    case E1000_DEV_ID_82540EP_LOM:
+    case E1000_DEV_ID_82540EP_LP:
+    case E1000_DEV_ID_82540EM:
+    case E1000_DEV_ID_82540EM_LOM:
+    case E1000_DEV_ID_82545EM_COPPER:
+    case E1000_DEV_ID_82545EM_FIBER:
+    case E1000_DEV_ID_82546EB_COPPER:
+    case E1000_DEV_ID_82546EB_FIBER:
+        /* Restore LEDCTL settings */
+        E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_default);
+        break;
+    default:
+        DEBUGOUT("Invalid device ID\n");
+        return -E1000_ERR_CONFIG;
+    }
+    return 0;
+}
+    
+/******************************************************************************
+ * Turns on the software controllable LED
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+e1000_led_on(struct e1000_hw *hw)
+{
+    uint32_t ctrl;
+
+    DEBUGFUNC("e1000_led_on");
+
+    switch(hw->device_id) {
+    case E1000_DEV_ID_82542:
+    case E1000_DEV_ID_82543GC_FIBER:
+    case E1000_DEV_ID_82543GC_COPPER:
+    case E1000_DEV_ID_82544EI_FIBER:
+        ctrl = E1000_READ_REG(hw, CTRL);
+        /* Set SW Defineable Pin 0 to turn on the LED */
+        ctrl |= E1000_CTRL_SWDPIN0;
+        ctrl |= E1000_CTRL_SWDPIO0;
+        E1000_WRITE_REG(hw, CTRL, ctrl);
+        break;
+    case E1000_DEV_ID_82544EI_COPPER:
+    case E1000_DEV_ID_82544GC_COPPER:
+    case E1000_DEV_ID_82544GC_LOM:
+    case E1000_DEV_ID_82545EM_FIBER:
+    case E1000_DEV_ID_82546EB_FIBER:
+        ctrl = E1000_READ_REG(hw, CTRL);
+        /* Clear SW Defineable Pin 0 to turn on the LED */
+        ctrl &= ~E1000_CTRL_SWDPIN0;
+        ctrl |= E1000_CTRL_SWDPIO0;
+        E1000_WRITE_REG(hw, CTRL, ctrl);
+        break;
+    case E1000_DEV_ID_82540EP:
+    case E1000_DEV_ID_82540EP_LOM:
+    case E1000_DEV_ID_82540EP_LP:
+    case E1000_DEV_ID_82540EM:
+    case E1000_DEV_ID_82540EM_LOM:
+    case E1000_DEV_ID_82545EM_COPPER:
+    case E1000_DEV_ID_82546EB_COPPER:
+        E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode2);
+        break;
+    default:
+        DEBUGOUT("Invalid device ID\n");
+        return -E1000_ERR_CONFIG;
+    }
+    return 0;
+}
+
+/******************************************************************************
+ * Turns off the software controllable LED
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+int32_t
+e1000_led_off(struct e1000_hw *hw)
+{
+    uint32_t ctrl;
+
+    DEBUGFUNC("e1000_led_off");
+
+    switch(hw->device_id) {
+    case E1000_DEV_ID_82542:
+    case E1000_DEV_ID_82543GC_FIBER:
+    case E1000_DEV_ID_82543GC_COPPER:
+    case E1000_DEV_ID_82544EI_FIBER:
+        ctrl = E1000_READ_REG(hw, CTRL);
+        /* Clear SW Defineable Pin 0 to turn off the LED */
+        ctrl &= ~E1000_CTRL_SWDPIN0;
+        ctrl |= E1000_CTRL_SWDPIO0;
+        E1000_WRITE_REG(hw, CTRL, ctrl);
+        break;
+    case E1000_DEV_ID_82544EI_COPPER:
+    case E1000_DEV_ID_82544GC_COPPER:
+    case E1000_DEV_ID_82544GC_LOM:
+    case E1000_DEV_ID_82545EM_FIBER:
+    case E1000_DEV_ID_82546EB_FIBER:
+        ctrl = E1000_READ_REG(hw, CTRL);
+        /* Set SW Defineable Pin 0 to turn off the LED */
+        ctrl |= E1000_CTRL_SWDPIN0;
+        ctrl |= E1000_CTRL_SWDPIO0;
+        E1000_WRITE_REG(hw, CTRL, ctrl);
+        break;
+    case E1000_DEV_ID_82540EP:
+    case E1000_DEV_ID_82540EP_LOM:
+    case E1000_DEV_ID_82540EP_LP:
+    case E1000_DEV_ID_82540EM:
+    case E1000_DEV_ID_82540EM_LOM:
+    case E1000_DEV_ID_82545EM_COPPER:
+    case E1000_DEV_ID_82546EB_COPPER:
+        E1000_WRITE_REG(hw, LEDCTL, hw->ledctl_mode1);
+        break;
+    default:
+        DEBUGOUT("Invalid device ID\n");
+        return -E1000_ERR_CONFIG;
+    }
+    return 0;
+}
+
+/******************************************************************************
+ * Clears all hardware statistics counters. 
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+void
+e1000_clear_hw_cntrs(struct e1000_hw *hw)
+{
+    volatile uint32_t temp;
+
+    temp = E1000_READ_REG(hw, CRCERRS);
+    temp = E1000_READ_REG(hw, SYMERRS);
+    temp = E1000_READ_REG(hw, MPC);
+    temp = E1000_READ_REG(hw, SCC);
+    temp = E1000_READ_REG(hw, ECOL);
+    temp = E1000_READ_REG(hw, MCC);
+    temp = E1000_READ_REG(hw, LATECOL);
+    temp = E1000_READ_REG(hw, COLC);
+    temp = E1000_READ_REG(hw, DC);
+    temp = E1000_READ_REG(hw, SEC);
+    temp = E1000_READ_REG(hw, RLEC);
+    temp = E1000_READ_REG(hw, XONRXC);
+    temp = E1000_READ_REG(hw, XONTXC);
+    temp = E1000_READ_REG(hw, XOFFRXC);
+    temp = E1000_READ_REG(hw, XOFFTXC);
+    temp = E1000_READ_REG(hw, FCRUC);
+    temp = E1000_READ_REG(hw, PRC64);
+    temp = E1000_READ_REG(hw, PRC127);
+    temp = E1000_READ_REG(hw, PRC255);
+    temp = E1000_READ_REG(hw, PRC511);
+    temp = E1000_READ_REG(hw, PRC1023);
+    temp = E1000_READ_REG(hw, PRC1522);
+    temp = E1000_READ_REG(hw, GPRC);
+    temp = E1000_READ_REG(hw, BPRC);
+    temp = E1000_READ_REG(hw, MPRC);
+    temp = E1000_READ_REG(hw, GPTC);
+    temp = E1000_READ_REG(hw, GORCL);
+    temp = E1000_READ_REG(hw, GORCH);
+    temp = E1000_READ_REG(hw, GOTCL);
+    temp = E1000_READ_REG(hw, GOTCH);
+    temp = E1000_READ_REG(hw, RNBC);
+    temp = E1000_READ_REG(hw, RUC);
+    temp = E1000_READ_REG(hw, RFC);
+    temp = E1000_READ_REG(hw, ROC);
+    temp = E1000_READ_REG(hw, RJC);
+    temp = E1000_READ_REG(hw, TORL);
+    temp = E1000_READ_REG(hw, TORH);
+    temp = E1000_READ_REG(hw, TOTL);
+    temp = E1000_READ_REG(hw, TOTH);
+    temp = E1000_READ_REG(hw, TPR);
+    temp = E1000_READ_REG(hw, TPT);
+    temp = E1000_READ_REG(hw, PTC64);
+    temp = E1000_READ_REG(hw, PTC127);
+    temp = E1000_READ_REG(hw, PTC255);
+    temp = E1000_READ_REG(hw, PTC511);
+    temp = E1000_READ_REG(hw, PTC1023);
+    temp = E1000_READ_REG(hw, PTC1522);
+    temp = E1000_READ_REG(hw, MPTC);
+    temp = E1000_READ_REG(hw, BPTC);
+
+    if(hw->mac_type < e1000_82543) return;
+
+    temp = E1000_READ_REG(hw, ALGNERRC);
+    temp = E1000_READ_REG(hw, RXERRC);
+    temp = E1000_READ_REG(hw, TNCRS);
+    temp = E1000_READ_REG(hw, CEXTERR);
+    temp = E1000_READ_REG(hw, TSCTC);
+    temp = E1000_READ_REG(hw, TSCTFC);
+
+    if(hw->mac_type <= e1000_82544) return;
+
+    temp = E1000_READ_REG(hw, MGTPRC);
+    temp = E1000_READ_REG(hw, MGTPDC);
+    temp = E1000_READ_REG(hw, MGTPTC);
+}
+
+/******************************************************************************
+ * Resets Adaptive IFS to its default state.
+ *
+ * hw - Struct containing variables accessed by shared code
+ *
+ * Call this after e1000_init_hw. You may override the IFS defaults by setting
+ * hw->ifs_params_forced to TRUE. However, you must initialize hw->
+ * current_ifs_val, ifs_min_val, ifs_max_val, ifs_step_size, and ifs_ratio
+ * before calling this function.
+ *****************************************************************************/
+void
+e1000_reset_adaptive(struct e1000_hw *hw)
+{
+    DEBUGFUNC("e1000_reset_adaptive");
+
+    if(hw->adaptive_ifs) {
+        if(!hw->ifs_params_forced) {
+            hw->current_ifs_val = 0;
+            hw->ifs_min_val = IFS_MIN;
+            hw->ifs_max_val = IFS_MAX;
+            hw->ifs_step_size = IFS_STEP;
+            hw->ifs_ratio = IFS_RATIO;
+        }
+        hw->in_ifs_mode = FALSE;
+        E1000_WRITE_REG(hw, AIT, 0);
+    } else {
+        DEBUGOUT("Not in Adaptive IFS mode!\n");
+    }
+}
+
+/******************************************************************************
+ * Called during the callback/watchdog routine to update IFS value based on
+ * the ratio of transmits to collisions.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * tx_packets - Number of transmits since last callback
+ * total_collisions - Number of collisions since last callback
+ *****************************************************************************/
+void
+e1000_update_adaptive(struct e1000_hw *hw)
+{
+    DEBUGFUNC("e1000_update_adaptive");
+
+    if(hw->adaptive_ifs) {
+        if((hw->collision_delta * hw->ifs_ratio) > 
+           hw->tx_packet_delta) {
+            if(hw->tx_packet_delta > MIN_NUM_XMITS) {
+                hw->in_ifs_mode = TRUE;
+                if(hw->current_ifs_val < hw->ifs_max_val) {
+                    if(hw->current_ifs_val == 0)
+                        hw->current_ifs_val = hw->ifs_min_val;
+                    else
+                        hw->current_ifs_val += hw->ifs_step_size;
+                    E1000_WRITE_REG(hw, AIT, hw->current_ifs_val);
+                }
+            }
+        } else {
+            if((hw->in_ifs_mode == TRUE) && 
+               (hw->tx_packet_delta <= MIN_NUM_XMITS)) {
+                hw->current_ifs_val = 0;
+                hw->in_ifs_mode = FALSE;
+                E1000_WRITE_REG(hw, AIT, 0);
+            }
+        }
+    } else {
+        DEBUGOUT("Not in Adaptive IFS mode!\n");
+    }
+}
+
+/******************************************************************************
+ * Adjusts the statistic counters when a frame is accepted by TBI_ACCEPT
+ * 
+ * hw - Struct containing variables accessed by shared code
+ * frame_len - The length of the frame in question
+ * mac_addr - The Ethernet destination address of the frame in question
+ *****************************************************************************/
+void
+e1000_tbi_adjust_stats(struct e1000_hw *hw,
+                       struct e1000_hw_stats *stats,
+                       uint32_t frame_len,
+                       uint8_t *mac_addr)
+{
+    uint64_t carry_bit;
+
+    /* First adjust the frame length. */
+    frame_len--;
+    /* We need to adjust the statistics counters, since the hardware
+     * counters overcount this packet as a CRC error and undercount
+     * the packet as a good packet
+     */
+    /* This packet should not be counted as a CRC error.    */
+    stats->crcerrs--;
+    /* This packet does count as a Good Packet Received.    */
+    stats->gprc++;
+
+    /* Adjust the Good Octets received counters             */
+    carry_bit = 0x80000000 & stats->gorcl;
+    stats->gorcl += frame_len;
+    /* If the high bit of Gorcl (the low 32 bits of the Good Octets
+     * Received Count) was one before the addition, 
+     * AND it is zero after, then we lost the carry out, 
+     * need to add one to Gorch (Good Octets Received Count High).
+     * This could be simplified if all environments supported 
+     * 64-bit integers.
+     */
+    if(carry_bit && ((stats->gorcl & 0x80000000) == 0))
+        stats->gorch++;
+    /* Is this a broadcast or multicast?  Check broadcast first,
+     * since the test for a multicast frame will test positive on 
+     * a broadcast frame.
+     */
+    if((mac_addr[0] == (uint8_t) 0xff) && (mac_addr[1] == (uint8_t) 0xff))
+        /* Broadcast packet */
+        stats->bprc++;
+    else if(*mac_addr & 0x01)
+        /* Multicast packet */
+        stats->mprc++;
+
+    if(frame_len == hw->max_frame_size) {
+        /* In this case, the hardware has overcounted the number of
+         * oversize frames.
+         */
+        if(stats->roc > 0)
+            stats->roc--;
+    }
+
+    /* Adjust the bin counters when the extra byte put the frame in the
+     * wrong bin. Remember that the frame_len was adjusted above.
+     */
+    if(frame_len == 64) {
+        stats->prc64++;
+        stats->prc127--;
+    } else if(frame_len == 127) {
+        stats->prc127++;
+        stats->prc255--;
+    } else if(frame_len == 255) {
+        stats->prc255++;
+        stats->prc511--;
+    } else if(frame_len == 511) {
+        stats->prc511++;
+        stats->prc1023--;
+    } else if(frame_len == 1023) {
+        stats->prc1023++;
+        stats->prc1522--;
+    } else if(frame_len == 1522) {
+        stats->prc1522++;
+    }
+}
+
+/******************************************************************************
+ * Gets the current PCI bus type, speed, and width of the hardware
+ *
+ * hw - Struct containing variables accessed by shared code
+ *****************************************************************************/
+void
+e1000_get_bus_info(struct e1000_hw *hw)
+{
+    uint32_t status;
+
+    if(hw->mac_type < e1000_82543) {
+        hw->bus_type = e1000_bus_type_unknown;
+        hw->bus_speed = e1000_bus_speed_unknown;
+        hw->bus_width = e1000_bus_width_unknown;
+        return;
+    }
+
+    status = E1000_READ_REG(hw, STATUS);
+    hw->bus_type = (status & E1000_STATUS_PCIX_MODE) ?
+                   e1000_bus_type_pcix : e1000_bus_type_pci;
+    if(hw->bus_type == e1000_bus_type_pci) {
+        hw->bus_speed = (status & E1000_STATUS_PCI66) ?
+                        e1000_bus_speed_66 : e1000_bus_speed_33;
+    } else {
+        switch (status & E1000_STATUS_PCIX_SPEED) {
+        case E1000_STATUS_PCIX_SPEED_66:
+            hw->bus_speed = e1000_bus_speed_66;
+            break;
+        case E1000_STATUS_PCIX_SPEED_100:
+            hw->bus_speed = e1000_bus_speed_100;
+            break;
+        case E1000_STATUS_PCIX_SPEED_133:
+            hw->bus_speed = e1000_bus_speed_133;
+            break;
+        default:
+            hw->bus_speed = e1000_bus_speed_reserved;
+            break;
+        }
+    }
+    hw->bus_width = (status & E1000_STATUS_BUS64) ?
+                    e1000_bus_width_64 : e1000_bus_width_32;
+}
+/******************************************************************************
+ * Reads a value from one of the devices registers using port I/O (as opposed
+ * memory mapped I/O). Only 82544 and newer devices support port I/O.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset to read from
+ *****************************************************************************/
+uint32_t
+e1000_read_reg_io(struct e1000_hw *hw,
+                  uint32_t offset)
+{
+    uint32_t io_addr = hw->io_base;
+    uint32_t io_data = hw->io_base + 4;
+
+    e1000_io_write(hw, io_addr, offset);
+    return e1000_io_read(hw, io_data);
+}
+
+/******************************************************************************
+ * Writes a value to one of the devices registers using port I/O (as opposed to
+ * memory mapped I/O). Only 82544 and newer devices support port I/O.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * offset - offset to write to
+ * value - value to write
+ *****************************************************************************/
+void
+e1000_write_reg_io(struct e1000_hw *hw,
+                   uint32_t offset,
+                   uint32_t value)
+{
+    uint32_t io_addr = hw->io_base;
+    uint32_t io_data = hw->io_base + 4;
+
+    e1000_io_write(hw, io_addr, offset);
+    e1000_io_write(hw, io_data, value);
+}
+
diff --git a/xen-2.4.16/drivers/net/e1000/e1000_hw.h b/xen-2.4.16/drivers/net/e1000/e1000_hw.h
new file mode 100644 (file)
index 0000000..812dfd1
--- /dev/null
@@ -0,0 +1,1789 @@
+/*******************************************************************************
+
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  This program is free software; you can redistribute it and/or modify it 
+  under the terms of the GNU General Public License as published by the Free 
+  Software Foundation; either version 2 of the License, or (at your option) 
+  any later version.
+  
+  This program is distributed in the hope that it will be useful, but WITHOUT 
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+  more details.
+  
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59 
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+/* e1000_hw.h
+ * Structures, enums, and macros for the MAC
+ */
+
+#ifndef _E1000_HW_H_
+#define _E1000_HW_H_
+
+#include "e1000_osdep.h"
+
+/* Forward declarations of structures used by the shared code */
+struct e1000_hw;
+struct e1000_hw_stats;
+
+/* Enumerated types specific to the e1000 hardware */
+/* Media Access Controlers */
+typedef enum {
+    e1000_undefined = 0,
+    e1000_82542_rev2_0,
+    e1000_82542_rev2_1,
+    e1000_82543,
+    e1000_82544,
+    e1000_82540,
+    e1000_82545,
+    e1000_82546,
+    e1000_num_macs
+} e1000_mac_type;
+
+/* Media Types */
+typedef enum {
+    e1000_media_type_copper = 0,
+    e1000_media_type_fiber = 1,
+    e1000_num_media_types
+} e1000_media_type;
+
+typedef enum {
+    e1000_10_half = 0,
+    e1000_10_full = 1,
+    e1000_100_half = 2,
+    e1000_100_full = 3
+} e1000_speed_duplex_type;
+
+/* Flow Control Settings */
+typedef enum {
+    e1000_fc_none = 0,
+    e1000_fc_rx_pause = 1,
+    e1000_fc_tx_pause = 2,
+    e1000_fc_full = 3,
+    e1000_fc_default = 0xFF
+} e1000_fc_type;
+
+/* PCI bus types */
+typedef enum {
+    e1000_bus_type_unknown = 0,
+    e1000_bus_type_pci,
+    e1000_bus_type_pcix
+} e1000_bus_type;
+
+/* PCI bus speeds */
+typedef enum {
+    e1000_bus_speed_unknown = 0,
+    e1000_bus_speed_33,
+    e1000_bus_speed_66,
+    e1000_bus_speed_100,
+    e1000_bus_speed_133,
+    e1000_bus_speed_reserved
+} e1000_bus_speed;
+
+/* PCI bus widths */
+typedef enum {
+    e1000_bus_width_unknown = 0,
+    e1000_bus_width_32,
+    e1000_bus_width_64
+} e1000_bus_width;
+
+/* PHY status info structure and supporting enums */
+typedef enum {
+    e1000_cable_length_50 = 0,
+    e1000_cable_length_50_80,
+    e1000_cable_length_80_110,
+    e1000_cable_length_110_140,
+    e1000_cable_length_140,
+    e1000_cable_length_undefined = 0xFF
+} e1000_cable_length;
+
+typedef enum {
+    e1000_10bt_ext_dist_enable_normal = 0,
+    e1000_10bt_ext_dist_enable_lower,
+    e1000_10bt_ext_dist_enable_undefined = 0xFF
+} e1000_10bt_ext_dist_enable;
+
+typedef enum {
+    e1000_rev_polarity_normal = 0,
+    e1000_rev_polarity_reversed,
+    e1000_rev_polarity_undefined = 0xFF
+} e1000_rev_polarity;
+
+typedef enum {
+    e1000_polarity_reversal_enabled = 0,
+    e1000_polarity_reversal_disabled,
+    e1000_polarity_reversal_undefined = 0xFF
+} e1000_polarity_reversal;
+
+typedef enum {
+    e1000_auto_x_mode_manual_mdi = 0,
+    e1000_auto_x_mode_manual_mdix,
+    e1000_auto_x_mode_auto1,
+    e1000_auto_x_mode_auto2,
+    e1000_auto_x_mode_undefined = 0xFF
+} e1000_auto_x_mode;
+
+typedef enum {
+    e1000_1000t_rx_status_not_ok = 0,
+    e1000_1000t_rx_status_ok,
+    e1000_1000t_rx_status_undefined = 0xFF
+} e1000_1000t_rx_status;
+
+struct e1000_phy_info {
+    e1000_cable_length cable_length;
+    e1000_10bt_ext_dist_enable extended_10bt_distance;
+    e1000_rev_polarity cable_polarity;
+    e1000_polarity_reversal polarity_correction;
+    e1000_auto_x_mode mdix_mode;
+    e1000_1000t_rx_status local_rx;
+    e1000_1000t_rx_status remote_rx;
+};
+
+struct e1000_phy_stats {
+    uint32_t idle_errors;
+    uint32_t receive_errors;
+};
+
+
+
+/* Error Codes */
+#define E1000_SUCCESS      0
+#define E1000_ERR_EEPROM   1
+#define E1000_ERR_PHY      2
+#define E1000_ERR_CONFIG   3
+#define E1000_ERR_PARAM    4
+#define E1000_ERR_MAC_TYPE 5
+
+/* Function prototypes */
+/* Initialization */
+void e1000_reset_hw(struct e1000_hw *hw);
+int32_t e1000_init_hw(struct e1000_hw *hw);
+int32_t e1000_set_mac_type(struct e1000_hw *hw);
+
+/* Link Configuration */
+int32_t e1000_setup_link(struct e1000_hw *hw);
+int32_t e1000_phy_setup_autoneg(struct e1000_hw *hw);
+void e1000_config_collision_dist(struct e1000_hw *hw);
+int32_t e1000_config_fc_after_link_up(struct e1000_hw *hw);
+int32_t e1000_check_for_link(struct e1000_hw *hw);
+void e1000_get_speed_and_duplex(struct e1000_hw *hw, uint16_t * speed, uint16_t * duplex);
+int32_t e1000_wait_autoneg(struct e1000_hw *hw);
+
+/* PHY */
+int32_t e1000_read_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t *phy_data);
+int32_t e1000_write_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t data);
+void e1000_phy_hw_reset(struct e1000_hw *hw);
+int32_t e1000_phy_reset(struct e1000_hw *hw);
+int32_t e1000_detect_gig_phy(struct e1000_hw *hw);
+int32_t e1000_phy_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info);
+int32_t e1000_validate_mdi_setting(struct e1000_hw *hw);
+
+/* EEPROM Functions */
+int32_t e1000_read_eeprom(struct e1000_hw *hw, uint16_t reg, uint16_t *data);
+int32_t e1000_validate_eeprom_checksum(struct e1000_hw *hw);
+int32_t e1000_update_eeprom_checksum(struct e1000_hw *hw);
+int32_t e1000_write_eeprom(struct e1000_hw *hw, uint16_t reg, uint16_t data);
+int32_t e1000_read_part_num(struct e1000_hw *hw, uint32_t * part_num);
+int32_t e1000_read_mac_addr(struct e1000_hw * hw);
+
+/* Filters (multicast, vlan, receive) */
+void e1000_init_rx_addrs(struct e1000_hw *hw);
+void e1000_mc_addr_list_update(struct e1000_hw *hw, uint8_t * mc_addr_list, uint32_t mc_addr_count, uint32_t pad);
+uint32_t e1000_hash_mc_addr(struct e1000_hw *hw, uint8_t * mc_addr);
+void e1000_mta_set(struct e1000_hw *hw, uint32_t hash_value);
+void e1000_rar_set(struct e1000_hw *hw, uint8_t * mc_addr, uint32_t rar_index);
+void e1000_write_vfta(struct e1000_hw *hw, uint32_t offset, uint32_t value);
+void e1000_clear_vfta(struct e1000_hw *hw);
+
+/* LED functions */
+int32_t e1000_setup_led(struct e1000_hw *hw);
+int32_t e1000_cleanup_led(struct e1000_hw *hw);
+int32_t e1000_led_on(struct e1000_hw *hw);
+int32_t e1000_led_off(struct e1000_hw *hw);
+
+/* Adaptive IFS Functions */
+
+/* Everything else */
+void e1000_clear_hw_cntrs(struct e1000_hw *hw);
+void e1000_reset_adaptive(struct e1000_hw *hw);
+void e1000_update_adaptive(struct e1000_hw *hw);
+void e1000_tbi_adjust_stats(struct e1000_hw *hw, struct e1000_hw_stats *stats, uint32_t frame_len, uint8_t * mac_addr);
+void e1000_get_bus_info(struct e1000_hw *hw);
+void e1000_pci_set_mwi(struct e1000_hw *hw);
+void e1000_pci_clear_mwi(struct e1000_hw *hw);
+void e1000_read_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value);
+void e1000_write_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value);
+/* Port I/O is only supported on 82544 and newer */
+uint32_t e1000_io_read(struct e1000_hw *hw, uint32_t port);
+uint32_t e1000_read_reg_io(struct e1000_hw *hw, uint32_t offset);
+void e1000_io_write(struct e1000_hw *hw, uint32_t port, uint32_t value);
+void e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset, uint32_t value);
+#define E1000_READ_REG_IO(a, reg) \
+    e1000_read_reg_io((a), E1000_##reg)
+#define E1000_WRITE_REG_IO(a, reg, val) \
+    e1000_write_reg_io((a), E1000_##reg, val)
+
+/* PCI Device IDs */
+#define E1000_DEV_ID_82542               0x1000
+#define E1000_DEV_ID_82543GC_FIBER       0x1001
+#define E1000_DEV_ID_82543GC_COPPER      0x1004
+#define E1000_DEV_ID_82544EI_COPPER      0x1008
+#define E1000_DEV_ID_82544EI_FIBER       0x1009
+#define E1000_DEV_ID_82544GC_COPPER      0x100C
+#define E1000_DEV_ID_82544GC_LOM         0x100D
+#define E1000_DEV_ID_82540EM             0x100E
+#define E1000_DEV_ID_82540EM_LOM         0x1015
+#define E1000_DEV_ID_82540EP_LOM         0x1016
+#define E1000_DEV_ID_82540EP             0x1017
+#define E1000_DEV_ID_82540EP_LP          0x101E
+#define E1000_DEV_ID_82545EM_COPPER      0x100F
+#define E1000_DEV_ID_82545EM_FIBER       0x1011
+#define E1000_DEV_ID_82546EB_COPPER      0x1010
+#define E1000_DEV_ID_82546EB_FIBER       0x1012
+#define NUM_DEV_IDS 16
+
+#define NODE_ADDRESS_SIZE 6
+#define ETH_LENGTH_OF_ADDRESS 6
+
+/* MAC decode size is 128K - This is the size of BAR0 */
+#define MAC_DECODE_SIZE (128 * 1024)
+
+#define E1000_82542_2_0_REV_ID 2
+#define E1000_82542_2_1_REV_ID 3
+
+#define SPEED_10    10
+#define SPEED_100   100
+#define SPEED_1000  1000
+#define HALF_DUPLEX 1
+#define FULL_DUPLEX 2
+
+/* The sizes (in bytes) of a ethernet packet */
+#define ENET_HEADER_SIZE             14
+#define MAXIMUM_ETHERNET_FRAME_SIZE  1518 /* With FCS */
+#define MINIMUM_ETHERNET_FRAME_SIZE  64   /* With FCS */
+#define ETHERNET_FCS_SIZE            4
+#define MAXIMUM_ETHERNET_PACKET_SIZE \
+    (MAXIMUM_ETHERNET_FRAME_SIZE - ETHERNET_FCS_SIZE)
+#define MINIMUM_ETHERNET_PACKET_SIZE \
+    (MINIMUM_ETHERNET_FRAME_SIZE - ETHERNET_FCS_SIZE)
+#define CRC_LENGTH                   ETHERNET_FCS_SIZE
+#define MAX_JUMBO_FRAME_SIZE         0x3F00
+
+
+/* 802.1q VLAN Packet Sizes */
+#define VLAN_TAG_SIZE                     4     /* 802.3ac tag (not DMAed) */
+
+/* Ethertype field values */
+#define ETHERNET_IEEE_VLAN_TYPE 0x8100  /* 802.3ac packet */
+#define ETHERNET_IP_TYPE        0x0800  /* IP packets */
+#define ETHERNET_ARP_TYPE       0x0806  /* Address Resolution Protocol (ARP) */
+
+/* Packet Header defines */
+#define IP_PROTOCOL_TCP    6
+#define IP_PROTOCOL_UDP    0x11
+
+/* This defines the bits that are set in the Interrupt Mask
+ * Set/Read Register.  Each bit is documented below:
+ *   o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
+ *   o RXSEQ  = Receive Sequence Error 
+ */
+#define POLL_IMS_ENABLE_MASK ( \
+    E1000_IMS_RXDMT0 |         \
+    E1000_IMS_RXSEQ)
+
+/* This defines the bits that are set in the Interrupt Mask
+ * Set/Read Register.  Each bit is documented below:
+ *   o RXT0   = Receiver Timer Interrupt (ring 0)
+ *   o TXDW   = Transmit Descriptor Written Back
+ *   o RXDMT0 = Receive Descriptor Minimum Threshold hit (ring 0)
+ *   o RXSEQ  = Receive Sequence Error
+ *   o LSC    = Link Status Change
+ */
+#define IMS_ENABLE_MASK ( \
+    E1000_IMS_RXT0   |    \
+    E1000_IMS_TXDW   |    \
+    E1000_IMS_RXDMT0 |    \
+    E1000_IMS_RXSEQ  |    \
+    E1000_IMS_LSC)
+
+/* The number of high/low register pairs in the RAR. The RAR (Receive Address
+ * Registers) holds the directed and multicast addresses that we monitor. We
+ * reserve one of these spots for our directed address, allowing us room for
+ * E1000_RAR_ENTRIES - 1 multicast addresses. 
+ */
+#define E1000_RAR_ENTRIES 16
+
+#define MIN_NUMBER_OF_DESCRIPTORS 8
+#define MAX_NUMBER_OF_DESCRIPTORS 0xFFF8
+
+/* Receive Descriptor */
+struct e1000_rx_desc {
+    uint64_t buffer_addr; /* Address of the descriptor's data buffer */
+    uint16_t length;     /* Length of data DMAed into data buffer */
+    uint16_t csum;       /* Packet checksum */
+    uint8_t status;      /* Descriptor status */
+    uint8_t errors;      /* Descriptor Errors */
+    uint16_t special;
+};
+
+/* Receive Decriptor bit definitions */
+#define E1000_RXD_STAT_DD       0x01    /* Descriptor Done */
+#define E1000_RXD_STAT_EOP      0x02    /* End of Packet */
+#define E1000_RXD_STAT_IXSM     0x04    /* Ignore checksum */
+#define E1000_RXD_STAT_VP       0x08    /* IEEE VLAN Packet */
+#define E1000_RXD_STAT_TCPCS    0x20    /* TCP xsum calculated */
+#define E1000_RXD_STAT_IPCS     0x40    /* IP xsum calculated */
+#define E1000_RXD_STAT_PIF      0x80    /* passed in-exact filter */
+#define E1000_RXD_ERR_CE        0x01    /* CRC Error */
+#define E1000_RXD_ERR_SE        0x02    /* Symbol Error */
+#define E1000_RXD_ERR_SEQ       0x04    /* Sequence Error */
+#define E1000_RXD_ERR_CXE       0x10    /* Carrier Extension Error */
+#define E1000_RXD_ERR_TCPE      0x20    /* TCP/UDP Checksum Error */
+#define E1000_RXD_ERR_IPE       0x40    /* IP Checksum Error */
+#define E1000_RXD_ERR_RXE       0x80    /* Rx Data Error */
+#define E1000_RXD_SPC_VLAN_MASK 0x0FFF  /* VLAN ID is in lower 12 bits */
+#define E1000_RXD_SPC_PRI_MASK  0xE000  /* Priority is in upper 3 bits */
+#define E1000_RXD_SPC_PRI_SHIFT 0x000D  /* Priority is in upper 3 of 16 */
+#define E1000_RXD_SPC_CFI_MASK  0x1000  /* CFI is bit 12 */
+#define E1000_RXD_SPC_CFI_SHIFT 0x000C  /* CFI is bit 12 */
+
+/* mask to determine if packets should be dropped due to frame errors */
+#define E1000_RXD_ERR_FRAME_ERR_MASK ( \
+    E1000_RXD_ERR_CE  |                \
+    E1000_RXD_ERR_SE  |                \
+    E1000_RXD_ERR_SEQ |                \
+    E1000_RXD_ERR_CXE |                \
+    E1000_RXD_ERR_RXE)
+
+/* Transmit Descriptor */
+struct e1000_tx_desc {
+    uint64_t buffer_addr;       /* Address of the descriptor's data buffer */
+    union {
+        uint32_t data;
+        struct {
+            uint16_t length;    /* Data buffer length */
+            uint8_t cso;        /* Checksum offset */
+            uint8_t cmd;        /* Descriptor control */
+        } flags;
+    } lower;
+    union {
+        uint32_t data;
+        struct {
+            uint8_t status;     /* Descriptor status */
+            uint8_t css;        /* Checksum start */
+            uint16_t special;
+        } fields;
+    } upper;
+};
+
+/* Transmit Descriptor bit definitions */
+#define E1000_TXD_DTYP_D     0x00100000 /* Data Descriptor */
+#define E1000_TXD_DTYP_C     0x00000000 /* Context Descriptor */
+#define E1000_TXD_POPTS_IXSM 0x01       /* Insert IP checksum */
+#define E1000_TXD_POPTS_TXSM 0x02       /* Insert TCP/UDP checksum */
+#define E1000_TXD_CMD_EOP    0x01000000 /* End of Packet */
+#define E1000_TXD_CMD_IFCS   0x02000000 /* Insert FCS (Ethernet CRC) */
+#define E1000_TXD_CMD_IC     0x04000000 /* Insert Checksum */
+#define E1000_TXD_CMD_RS     0x08000000 /* Report Status */
+#define E1000_TXD_CMD_RPS    0x10000000 /* Report Packet Sent */
+#define E1000_TXD_CMD_DEXT   0x20000000 /* Descriptor extension (0 = legacy) */
+#define E1000_TXD_CMD_VLE    0x40000000 /* Add VLAN tag */
+#define E1000_TXD_CMD_IDE    0x80000000 /* Enable Tidv register */
+#define E1000_TXD_STAT_DD    0x00000001 /* Descriptor Done */
+#define E1000_TXD_STAT_EC    0x00000002 /* Excess Collisions */
+#define E1000_TXD_STAT_LC    0x00000004 /* Late Collisions */
+#define E1000_TXD_STAT_TU    0x00000008 /* Transmit underrun */
+#define E1000_TXD_CMD_TCP    0x01000000 /* TCP packet */
+#define E1000_TXD_CMD_IP     0x02000000 /* IP packet */
+#define E1000_TXD_CMD_TSE    0x04000000 /* TCP Seg enable */
+#define E1000_TXD_STAT_TC    0x00000004 /* Tx Underrun */
+
+/* Offload Context Descriptor */
+struct e1000_context_desc {
+    union {
+        uint32_t ip_config;
+        struct {
+            uint8_t ipcss;      /* IP checksum start */
+            uint8_t ipcso;      /* IP checksum offset */
+            uint16_t ipcse;     /* IP checksum end */
+        } ip_fields;
+    } lower_setup;
+    union {
+        uint32_t tcp_config;
+        struct {
+            uint8_t tucss;      /* TCP checksum start */
+            uint8_t tucso;      /* TCP checksum offset */
+            uint16_t tucse;     /* TCP checksum end */
+        } tcp_fields;
+    } upper_setup;
+    uint32_t cmd_and_length;    /* */
+    union {
+        uint32_t data;
+        struct {
+            uint8_t status;     /* Descriptor status */
+            uint8_t hdr_len;    /* Header length */
+            uint16_t mss;       /* Maximum segment size */
+        } fields;
+    } tcp_seg_setup;
+};
+
+/* Offload data descriptor */
+struct e1000_data_desc {
+    uint64_t buffer_addr;       /* Address of the descriptor's buffer address */
+    union {
+        uint32_t data;
+        struct {
+            uint16_t length;    /* Data buffer length */
+            uint8_t typ_len_ext;        /* */
+            uint8_t cmd;        /* */
+        } flags;
+    } lower;
+    union {
+        uint32_t data;
+        struct {
+            uint8_t status;     /* Descriptor status */
+            uint8_t popts;      /* Packet Options */
+            uint16_t special;   /* */
+        } fields;
+    } upper;
+};
+
+/* Filters */
+#define E1000_NUM_UNICAST          16   /* Unicast filter entries */
+#define E1000_MC_TBL_SIZE          128  /* Multicast Filter Table (4096 bits) */
+#define E1000_VLAN_FILTER_TBL_SIZE 128  /* VLAN Filter Table (4096 bits) */
+
+
+/* Receive Address Register */
+struct e1000_rar {
+    volatile uint32_t low;      /* receive address low */
+    volatile uint32_t high;     /* receive address high */
+};
+
+/* The number of entries in the Multicast Table Array (MTA). */
+#define E1000_NUM_MTA_REGISTERS 128
+
+/* IPv4 Address Table Entry */
+struct e1000_ipv4_at_entry {
+    volatile uint32_t ipv4_addr;        /* IP Address (RW) */
+    volatile uint32_t reserved;
+};
+
+/* Four wakeup IP addresses are supported */
+#define E1000_WAKEUP_IP_ADDRESS_COUNT_MAX 4
+#define E1000_IP4AT_SIZE                  E1000_WAKEUP_IP_ADDRESS_COUNT_MAX
+#define E1000_IP6AT_SIZE                  1
+
+/* IPv6 Address Table Entry */
+struct e1000_ipv6_at_entry {
+    volatile uint8_t ipv6_addr[16];
+};
+
+/* Flexible Filter Length Table Entry */
+struct e1000_fflt_entry {
+    volatile uint32_t length;   /* Flexible Filter Length (RW) */
+    volatile uint32_t reserved;
+};
+
+/* Flexible Filter Mask Table Entry */
+struct e1000_ffmt_entry {
+    volatile uint32_t mask;     /* Flexible Filter Mask (RW) */
+    volatile uint32_t reserved;
+};
+
+/* Flexible Filter Value Table Entry */
+struct e1000_ffvt_entry {
+    volatile uint32_t value;    /* Flexible Filter Value (RW) */
+    volatile uint32_t reserved;
+};
+
+/* Four Flexible Filters are supported */
+#define E1000_FLEXIBLE_FILTER_COUNT_MAX 4
+
+/* Each Flexible Filter is at most 128 (0x80) bytes in length */
+#define E1000_FLEXIBLE_FILTER_SIZE_MAX  128
+
+#define E1000_FFLT_SIZE E1000_FLEXIBLE_FILTER_COUNT_MAX
+#define E1000_FFMT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
+#define E1000_FFVT_SIZE E1000_FLEXIBLE_FILTER_SIZE_MAX
+
+/* Register Set. (82543, 82544)
+ *
+ * Registers are defined to be 32 bits and  should be accessed as 32 bit values.
+ * These registers are physically located on the NIC, but are mapped into the 
+ * host memory address space.
+ *
+ * RW - register is both readable and writable
+ * RO - register is read only
+ * WO - register is write only
+ * R/clr - register is read only and is cleared when read
+ * A - register array
+ */
+#define E1000_CTRL     0x00000  /* Device Control - RW */
+#define E1000_STATUS   0x00008  /* Device Status - RO */
+#define E1000_EECD     0x00010  /* EEPROM/Flash Control - RW */
+#define E1000_EERD     0x00014  /* EEPROM Read - RW */
+#define E1000_CTRL_EXT 0x00018  /* Extended Device Control - RW */
+#define E1000_MDIC     0x00020  /* MDI Control - RW */
+#define E1000_FCAL     0x00028  /* Flow Control Address Low - RW */
+#define E1000_FCAH     0x0002C  /* Flow Control Address High -RW */
+#define E1000_FCT      0x00030  /* Flow Control Type - RW */
+#define E1000_VET      0x00038  /* VLAN Ether Type - RW */
+#define E1000_ICR      0x000C0  /* Interrupt Cause Read - R/clr */
+#define E1000_ITR      0x000C4  /* Interrupt Throttling Rate - RW */
+#define E1000_ICS      0x000C8  /* Interrupt Cause Set - WO */
+#define E1000_IMS      0x000D0  /* Interrupt Mask Set - RW */
+#define E1000_IMC      0x000D8  /* Interrupt Mask Clear - WO */
+#define E1000_RCTL     0x00100  /* RX Control - RW */
+#define E1000_FCTTV    0x00170  /* Flow Control Transmit Timer Value - RW */
+#define E1000_TXCW     0x00178  /* TX Configuration Word - RW */
+#define E1000_RXCW     0x00180  /* RX Configuration Word - RO */
+#define E1000_TCTL     0x00400  /* TX Control - RW */
+#define E1000_TIPG     0x00410  /* TX Inter-packet gap -RW */
+#define E1000_TBT      0x00448  /* TX Burst Timer - RW */
+#define E1000_AIT      0x00458  /* Adaptive Interframe Spacing Throttle - RW */
+#define E1000_LEDCTL   0x00E00  /* LED Control - RW */
+#define E1000_PBA      0x01000  /* Packet Buffer Allocation - RW */
+#define E1000_FCRTL    0x02160  /* Flow Control Receive Threshold Low - RW */
+#define E1000_FCRTH    0x02168  /* Flow Control Receive Threshold High - RW */
+#define E1000_RDBAL    0x02800  /* RX Descriptor Base Address Low - RW */
+#define E1000_RDBAH    0x02804  /* RX Descriptor Base Address High - RW */
+#define E1000_RDLEN    0x02808  /* RX Descriptor Length - RW */
+#define E1000_RDH      0x02810  /* RX Descriptor Head - RW */
+#define E1000_RDT      0x02818  /* RX Descriptor Tail - RW */
+#define E1000_RDTR     0x02820  /* RX Delay Timer - RW */
+#define E1000_RXDCTL   0x02828  /* RX Descriptor Control - RW */
+#define E1000_RADV     0x0282C  /* RX Interrupt Absolute Delay Timer - RW */
+#define E1000_RSRPD    0x02C00  /* RX Small Packet Detect - RW */
+#define E1000_TXDMAC   0x03000  /* TX DMA Control - RW */
+#define E1000_TDBAL    0x03800  /* TX Descriptor Base Address Low - RW */
+#define E1000_TDBAH    0x03804  /* TX Descriptor Base Address High - RW */
+#define E1000_TDLEN    0x03808  /* TX Descriptor Length - RW */
+#define E1000_TDH      0x03810  /* TX Descriptor Head - RW */
+#define E1000_TDT      0x03818  /* TX Descripotr Tail - RW */
+#define E1000_TIDV     0x03820  /* TX Interrupt Delay Value - RW */
+#define E1000_TXDCTL   0x03828  /* TX Descriptor Control - RW */
+#define E1000_TADV     0x0382C  /* TX Interrupt Absolute Delay Val - RW */
+#define E1000_TSPMT    0x03830  /* TCP Segmentation PAD & Min Threshold - RW */
+#define E1000_CRCERRS  0x04000  /* CRC Error Count - R/clr */
+#define E1000_ALGNERRC 0x04004  /* Alignment Error Count - R/clr */
+#define E1000_SYMERRS  0x04008  /* Symbol Error Count - R/clr */
+#define E1000_RXERRC   0x0400C  /* Receive Error Count - R/clr */
+#define E1000_MPC      0x04010  /* Missed Packet Count - R/clr */
+#define E1000_SCC      0x04014  /* Single Collision Count - R/clr */
+#define E1000_ECOL     0x04018  /* Excessive Collision Count - R/clr */
+#define E1000_MCC      0x0401C  /* Multiple Collision Count - R/clr */
+#define E1000_LATECOL  0x04020  /* Late Collision Count - R/clr */
+#define E1000_COLC     0x04028  /* Collision Count - R/clr */
+#define E1000_DC       0x04030  /* Defer Count - R/clr */
+#define E1000_TNCRS    0x04034  /* TX-No CRS - R/clr */
+#define E1000_SEC      0x04038  /* Sequence Error Count - R/clr */
+#define E1000_CEXTERR  0x0403C  /* Carrier Extension Error Count - R/clr */
+#define E1000_RLEC     0x04040  /* Receive Length Error Count - R/clr */
+#define E1000_XONRXC   0x04048  /* XON RX Count - R/clr */
+#define E1000_XONTXC   0x0404C  /* XON TX Count - R/clr */
+#define E1000_XOFFRXC  0x04050  /* XOFF RX Count - R/clr */
+#define E1000_XOFFTXC  0x04054  /* XOFF TX Count - R/clr */
+#define E1000_FCRUC    0x04058  /* Flow Control RX Unsupported Count- R/clr */
+#define E1000_PRC64    0x0405C  /* Packets RX (64 bytes) - R/clr */
+#define E1000_PRC127   0x04060  /* Packets RX (65-127 bytes) - R/clr */
+#define E1000_PRC255   0x04064  /* Packets RX (128-255 bytes) - R/clr */
+#define E1000_PRC511   0x04068  /* Packets RX (255-511 bytes) - R/clr */
+#define E1000_PRC1023  0x0406C  /* Packets RX (512-1023 bytes) - R/clr */
+#define E1000_PRC1522  0x04070  /* Packets RX (1024-1522 bytes) - R/clr */
+#define E1000_GPRC     0x04074  /* Good Packets RX Count - R/clr */
+#define E1000_BPRC     0x04078  /* Broadcast Packets RX Count - R/clr */
+#define E1000_MPRC     0x0407C  /* Multicast Packets RX Count - R/clr */
+#define E1000_GPTC     0x04080  /* Good Packets TX Count - R/clr */
+#define E1000_GORCL    0x04088  /* Good Octets RX Count Low - R/clr */
+#define E1000_GORCH    0x0408C  /* Good Octets RX Count High - R/clr */
+#define E1000_GOTCL    0x04090  /* Good Octets TX Count Low - R/clr */
+#define E1000_GOTCH    0x04094  /* Good Octets TX Count High - R/clr */
+#define E1000_RNBC     0x040A0  /* RX No Buffers Count - R/clr */
+#define E1000_RUC      0x040A4  /* RX Undersize Count - R/clr */
+#define E1000_RFC      0x040A8  /* RX Fragment Count - R/clr */
+#define E1000_ROC      0x040AC  /* RX Oversize Count - R/clr */
+#define E1000_RJC      0x040B0  /* RX Jabber Count - R/clr */
+#define E1000_MGTPRC   0x040B4  /* Management Packets RX Count - R/clr */
+#define E1000_MGTPDC   0x040B8  /* Management Packets Dropped Count - R/clr */
+#define E1000_MGTPTC   0x040BC  /* Management Packets TX Count - R/clr */
+#define E1000_TORL     0x040C0  /* Total Octets RX Low - R/clr */
+#define E1000_TORH     0x040C4  /* Total Octets RX High - R/clr */
+#define E1000_TOTL     0x040C8  /* Total Octets TX Low - R/clr */
+#define E1000_TOTH     0x040CC  /* Total Octets TX High - R/clr */
+#define E1000_TPR      0x040D0  /* Total Packets RX - R/clr */
+#define E1000_TPT      0x040D4  /* Total Packets TX - R/clr */
+#define E1000_PTC64    0x040D8  /* Packets TX (64 bytes) - R/clr */
+#define E1000_PTC127   0x040DC  /* Packets TX (65-127 bytes) - R/clr */
+#define E1000_PTC255   0x040E0  /* Packets TX (128-255 bytes) - R/clr */
+#define E1000_PTC511   0x040E4  /* Packets TX (256-511 bytes) - R/clr */
+#define E1000_PTC1023  0x040E8  /* Packets TX (512-1023 bytes) - R/clr */
+#define E1000_PTC1522  0x040EC  /* Packets TX (1024-1522 Bytes) - R/clr */
+#define E1000_MPTC     0x040F0  /* Multicast Packets TX Count - R/clr */
+#define E1000_BPTC     0x040F4  /* Broadcast Packets TX Count - R/clr */
+#define E1000_TSCTC    0x040F8  /* TCP Segmentation Context TX - R/clr */
+#define E1000_TSCTFC   0x040FC  /* TCP Segmentation Context TX Fail - R/clr */
+#define E1000_RXCSUM   0x05000  /* RX Checksum Control - RW */
+#define E1000_MTA      0x05200  /* Multicast Table Array - RW Array */
+#define E1000_RA       0x05400  /* Receive Address - RW Array */
+#define E1000_VFTA     0x05600  /* VLAN Filter Table Array - RW Array */
+#define E1000_WUC      0x05800  /* Wakeup Control - RW */
+#define E1000_WUFC     0x05808  /* Wakeup Filter Control - RW */
+#define E1000_WUS      0x05810  /* Wakeup Status - RO */
+#define E1000_MANC     0x05820  /* Management Control - RW */
+#define E1000_IPAV     0x05838  /* IP Address Valid - RW */
+#define E1000_IP4AT    0x05840  /* IPv4 Address Table - RW Array */
+#define E1000_IP6AT    0x05880  /* IPv6 Address Table - RW Array */
+#define E1000_WUPL     0x05900  /* Wakeup Packet Length - RW */
+#define E1000_WUPM     0x05A00  /* Wakeup Packet Memory - RO A */
+#define E1000_FFLT     0x05F00  /* Flexible Filter Length Table - RW Array */
+#define E1000_FFMT     0x09000  /* Flexible Filter Mask Table - RW Array */
+#define E1000_FFVT     0x09800  /* Flexible Filter Value Table - RW Array */
+
+/* Register Set (82542)
+ *
+ * Some of the 82542 registers are located at different offsets than they are
+ * in more current versions of the 8254x. Despite the difference in location,
+ * the registers function in the same manner.
+ */
+#define E1000_82542_CTRL     E1000_CTRL
+#define E1000_82542_STATUS   E1000_STATUS
+#define E1000_82542_EECD     E1000_EECD
+#define E1000_82542_EERD     E1000_EERD
+#define E1000_82542_CTRL_EXT E1000_CTRL_EXT
+#define E1000_82542_MDIC     E1000_MDIC
+#define E1000_82542_FCAL     E1000_FCAL
+#define E1000_82542_FCAH     E1000_FCAH
+#define E1000_82542_FCT      E1000_FCT
+#define E1000_82542_VET      E1000_VET
+#define E1000_82542_RA       0x00040
+#define E1000_82542_ICR      E1000_ICR
+#define E1000_82542_ITR      E1000_ITR
+#define E1000_82542_ICS      E1000_ICS
+#define E1000_82542_IMS      E1000_IMS
+#define E1000_82542_IMC      E1000_IMC
+#define E1000_82542_RCTL     E1000_RCTL
+#define E1000_82542_RDTR     0x00108
+#define E1000_82542_RDBAL    0x00110
+#define E1000_82542_RDBAH    0x00114
+#define E1000_82542_RDLEN    0x00118
+#define E1000_82542_RDH      0x00120
+#define E1000_82542_RDT      0x00128
+#define E1000_82542_FCRTH    0x00160
+#define E1000_82542_FCRTL    0x00168
+#define E1000_82542_FCTTV    E1000_FCTTV
+#define E1000_82542_TXCW     E1000_TXCW
+#define E1000_82542_RXCW     E1000_RXCW
+#define E1000_82542_MTA      0x00200
+#define E1000_82542_TCTL     E1000_TCTL
+#define E1000_82542_TIPG     E1000_TIPG
+#define E1000_82542_TDBAL    0x00420
+#define E1000_82542_TDBAH    0x00424
+#define E1000_82542_TDLEN    0x00428
+#define E1000_82542_TDH      0x00430
+#define E1000_82542_TDT      0x00438
+#define E1000_82542_TIDV     0x00440
+#define E1000_82542_TBT      E1000_TBT
+#define E1000_82542_AIT      E1000_AIT
+#define E1000_82542_VFTA     0x00600
+#define E1000_82542_LEDCTL   E1000_LEDCTL
+#define E1000_82542_PBA      E1000_PBA
+#define E1000_82542_RXDCTL   E1000_RXDCTL
+#define E1000_82542_RADV     E1000_RADV
+#define E1000_82542_RSRPD    E1000_RSRPD
+#define E1000_82542_TXDMAC   E1000_TXDMAC
+#define E1000_82542_TXDCTL   E1000_TXDCTL
+#define E1000_82542_TADV     E1000_TADV
+#define E1000_82542_TSPMT    E1000_TSPMT
+#define E1000_82542_CRCERRS  E1000_CRCERRS
+#define E1000_82542_ALGNERRC E1000_ALGNERRC
+#define E1000_82542_SYMERRS  E1000_SYMERRS
+#define E1000_82542_RXERRC   E1000_RXERRC
+#define E1000_82542_MPC      E1000_MPC
+#define E1000_82542_SCC      E1000_SCC
+#define E1000_82542_ECOL     E1000_ECOL
+#define E1000_82542_MCC      E1000_MCC
+#define E1000_82542_LATECOL  E1000_LATECOL
+#define E1000_82542_COLC     E1000_COLC
+#define E1000_82542_DC       E1000_DC
+#define E1000_82542_TNCRS    E1000_TNCRS
+#define E1000_82542_SEC      E1000_SEC
+#define E1000_82542_CEXTERR  E1000_CEXTERR
+#define E1000_82542_RLEC     E1000_RLEC
+#define E1000_82542_XONRXC   E1000_XONRXC
+#define E1000_82542_XONTXC   E1000_XONTXC
+#define E1000_82542_XOFFRXC  E1000_XOFFRXC
+#define E1000_82542_XOFFTXC  E1000_XOFFTXC
+#define E1000_82542_FCRUC    E1000_FCRUC
+#define E1000_82542_PRC64    E1000_PRC64
+#define E1000_82542_PRC127   E1000_PRC127
+#define E1000_82542_PRC255   E1000_PRC255
+#define E1000_82542_PRC511   E1000_PRC511
+#define E1000_82542_PRC1023  E1000_PRC1023
+#define E1000_82542_PRC1522  E1000_PRC1522
+#define E1000_82542_GPRC     E1000_GPRC
+#define E1000_82542_BPRC     E1000_BPRC
+#define E1000_82542_MPRC     E1000_MPRC
+#define E1000_82542_GPTC     E1000_GPTC
+#define E1000_82542_GORCL    E1000_GORCL
+#define E1000_82542_GORCH    E1000_GORCH
+#define E1000_82542_GOTCL    E1000_GOTCL
+#define E1000_82542_GOTCH    E1000_GOTCH
+#define E1000_82542_RNBC     E1000_RNBC
+#define E1000_82542_RUC      E1000_RUC
+#define E1000_82542_RFC      E1000_RFC
+#define E1000_82542_ROC      E1000_ROC
+#define E1000_82542_RJC      E1000_RJC
+#define E1000_82542_MGTPRC   E1000_MGTPRC
+#define E1000_82542_MGTPDC   E1000_MGTPDC
+#define E1000_82542_MGTPTC   E1000_MGTPTC
+#define E1000_82542_TORL     E1000_TORL
+#define E1000_82542_TORH     E1000_TORH
+#define E1000_82542_TOTL     E1000_TOTL
+#define E1000_82542_TOTH     E1000_TOTH
+#define E1000_82542_TPR      E1000_TPR
+#define E1000_82542_TPT      E1000_TPT
+#define E1000_82542_PTC64    E1000_PTC64
+#define E1000_82542_PTC127   E1000_PTC127
+#define E1000_82542_PTC255   E1000_PTC255
+#define E1000_82542_PTC511   E1000_PTC511
+#define E1000_82542_PTC1023  E1000_PTC1023
+#define E1000_82542_PTC1522  E1000_PTC1522
+#define E1000_82542_MPTC     E1000_MPTC
+#define E1000_82542_BPTC     E1000_BPTC
+#define E1000_82542_TSCTC    E1000_TSCTC
+#define E1000_82542_TSCTFC   E1000_TSCTFC
+#define E1000_82542_RXCSUM   E1000_RXCSUM
+#define E1000_82542_WUC      E1000_WUC
+#define E1000_82542_WUFC     E1000_WUFC
+#define E1000_82542_WUS      E1000_WUS
+#define E1000_82542_MANC     E1000_MANC
+#define E1000_82542_IPAV     E1000_IPAV
+#define E1000_82542_IP4AT    E1000_IP4AT
+#define E1000_82542_IP6AT    E1000_IP6AT
+#define E1000_82542_WUPL     E1000_WUPL
+#define E1000_82542_WUPM     E1000_WUPM
+#define E1000_82542_FFLT     E1000_FFLT
+#define E1000_82542_FFMT     E1000_FFMT
+#define E1000_82542_FFVT     E1000_FFVT
+
+/* Statistics counters collected by the MAC */
+struct e1000_hw_stats {
+    uint64_t crcerrs;
+    uint64_t algnerrc;
+    uint64_t symerrs;
+    uint64_t rxerrc;
+    uint64_t mpc;
+    uint64_t scc;
+    uint64_t ecol;
+    uint64_t mcc;
+    uint64_t latecol;
+    uint64_t colc;
+    uint64_t dc;
+    uint64_t tncrs;
+    uint64_t sec;
+    uint64_t cexterr;
+    uint64_t rlec;
+    uint64_t xonrxc;
+    uint64_t xontxc;
+    uint64_t xoffrxc;
+    uint64_t xofftxc;
+    uint64_t fcruc;
+    uint64_t prc64;
+    uint64_t prc127;
+    uint64_t prc255;
+    uint64_t prc511;
+    uint64_t prc1023;
+    uint64_t prc1522;
+    uint64_t gprc;
+    uint64_t bprc;
+    uint64_t mprc;
+    uint64_t gptc;
+    uint64_t gorcl;
+    uint64_t gorch;
+    uint64_t gotcl;
+    uint64_t gotch;
+    uint64_t rnbc;
+    uint64_t ruc;
+    uint64_t rfc;
+    uint64_t roc;
+    uint64_t rjc;
+    uint64_t mgprc;
+    uint64_t mgpdc;
+    uint64_t mgptc;
+    uint64_t torl;
+    uint64_t torh;
+    uint64_t totl;
+    uint64_t toth;
+    uint64_t tpr;
+    uint64_t tpt;
+    uint64_t ptc64;
+    uint64_t ptc127;
+    uint64_t ptc255;
+    uint64_t ptc511;
+    uint64_t ptc1023;
+    uint64_t ptc1522;
+    uint64_t mptc;
+    uint64_t bptc;
+    uint64_t tsctc;
+    uint64_t tsctfc;
+};
+
+/* Structure containing variables used by the shared code (e1000_hw.c) */
+struct e1000_hw {
+    uint8_t *hw_addr;
+    e1000_mac_type mac_type;
+    e1000_media_type media_type;
+    void *back;
+    e1000_fc_type fc;
+    e1000_bus_speed bus_speed;
+    e1000_bus_width bus_width;
+    e1000_bus_type bus_type;
+    uint32_t io_base;
+    uint32_t phy_id;
+    uint32_t phy_revision;
+    uint32_t phy_addr;
+    uint32_t original_fc;
+    uint32_t txcw;
+    uint32_t autoneg_failed;
+    uint32_t max_frame_size;
+    uint32_t min_frame_size;
+    uint32_t mc_filter_type;
+    uint32_t num_mc_addrs;
+    uint32_t collision_delta;
+    uint32_t tx_packet_delta;
+    uint32_t ledctl_default;
+    uint32_t ledctl_mode1;
+    uint32_t ledctl_mode2;
+    uint16_t autoneg_advertised;
+    uint16_t pci_cmd_word;
+    uint16_t fc_high_water;
+    uint16_t fc_low_water;
+    uint16_t fc_pause_time;
+    uint16_t current_ifs_val;
+    uint16_t ifs_min_val;
+    uint16_t ifs_max_val;
+    uint16_t ifs_step_size;
+    uint16_t ifs_ratio;
+    uint16_t device_id;
+    uint16_t vendor_id;
+    uint16_t subsystem_id;
+    uint16_t subsystem_vendor_id;
+    uint8_t revision_id;
+    uint8_t autoneg;
+    uint8_t mdix;
+    uint8_t forced_speed_duplex;
+    uint8_t wait_autoneg_complete;
+    uint8_t dma_fairness;
+    uint8_t mac_addr[NODE_ADDRESS_SIZE];
+    uint8_t perm_mac_addr[NODE_ADDRESS_SIZE];
+    boolean_t disable_polarity_correction;
+    boolean_t get_link_status;
+    boolean_t tbi_compatibility_en;
+    boolean_t tbi_compatibility_on;
+    boolean_t fc_send_xon;
+    boolean_t report_tx_early;
+    boolean_t adaptive_ifs;
+    boolean_t ifs_params_forced;
+    boolean_t in_ifs_mode;
+};
+
+
+#define E1000_EEPROM_SWDPIN0   0x0001   /* SWDPIN 0 EEPROM Value */
+#define E1000_EEPROM_LED_LOGIC 0x0020   /* Led Logic Word */
+
+/* Register Bit Masks */
+/* Device Control */
+#define E1000_CTRL_FD       0x00000001  /* Full duplex.0=half; 1=full */
+#define E1000_CTRL_BEM      0x00000002  /* Endian Mode.0=little,1=big */
+#define E1000_CTRL_PRIOR    0x00000004  /* Priority on PCI. 0=rx,1=fair */
+#define E1000_CTRL_LRST     0x00000008  /* Link reset. 0=normal,1=reset */
+#define E1000_CTRL_TME      0x00000010  /* Test mode. 0=normal,1=test */
+#define E1000_CTRL_SLE      0x00000020  /* Serial Link on 0=dis,1=en */
+#define E1000_CTRL_ASDE     0x00000020  /* Auto-speed detect enable */
+#define E1000_CTRL_SLU      0x00000040  /* Set link up (Force Link) */
+#define E1000_CTRL_ILOS     0x00000080  /* Invert Loss-Of Signal */
+#define E1000_CTRL_SPD_SEL  0x00000300  /* Speed Select Mask */
+#define E1000_CTRL_SPD_10   0x00000000  /* Force 10Mb */
+#define E1000_CTRL_SPD_100  0x00000100  /* Force 100Mb */
+#define E1000_CTRL_SPD_1000 0x00000200  /* Force 1Gb */
+#define E1000_CTRL_BEM32    0x00000400  /* Big Endian 32 mode */
+#define E1000_CTRL_FRCSPD   0x00000800  /* Force Speed */
+#define E1000_CTRL_FRCDPX   0x00001000  /* Force Duplex */
+#define E1000_CTRL_SWDPIN0  0x00040000  /* SWDPIN 0 value */
+#define E1000_CTRL_SWDPIN1  0x00080000  /* SWDPIN 1 value */
+#define E1000_CTRL_SWDPIN2  0x00100000  /* SWDPIN 2 value */
+#define E1000_CTRL_SWDPIN3  0x00200000  /* SWDPIN 3 value */
+#define E1000_CTRL_SWDPIO0  0x00400000  /* SWDPIN 0 Input or output */
+#define E1000_CTRL_SWDPIO1  0x00800000  /* SWDPIN 1 input or output */
+#define E1000_CTRL_SWDPIO2  0x01000000  /* SWDPIN 2 input or output */
+#define E1000_CTRL_SWDPIO3  0x02000000  /* SWDPIN 3 input or output */
+#define E1000_CTRL_RST      0x04000000  /* Global reset */
+#define E1000_CTRL_RFCE     0x08000000  /* Receive Flow Control enable */
+#define E1000_CTRL_TFCE     0x10000000  /* Transmit flow control enable */
+#define E1000_CTRL_RTE      0x20000000  /* Routing tag enable */
+#define E1000_CTRL_VME      0x40000000  /* IEEE VLAN mode enable */
+#define E1000_CTRL_PHY_RST  0x80000000  /* PHY Reset */
+
+/* Device Status */
+#define E1000_STATUS_FD         0x00000001      /* Full duplex.0=half,1=full */
+#define E1000_STATUS_LU         0x00000002      /* Link up.0=no,1=link */
+#define E1000_STATUS_FUNC_MASK  0x0000000C      /* PCI Function Mask */
+#define E1000_STATUS_FUNC_0     0x00000000      /* Function 0 */
+#define E1000_STATUS_FUNC_1     0x00000004      /* Function 1 */
+#define E1000_STATUS_TXOFF      0x00000010      /* transmission paused */
+#define E1000_STATUS_TBIMODE    0x00000020      /* TBI mode */
+#define E1000_STATUS_SPEED_MASK 0x000000C0
+#define E1000_STATUS_SPEED_10   0x00000000      /* Speed 10Mb/s */
+#define E1000_STATUS_SPEED_100  0x00000040      /* Speed 100Mb/s */
+#define E1000_STATUS_SPEED_1000 0x00000080      /* Speed 1000Mb/s */
+#define E1000_STATUS_ASDV       0x00000300      /* Auto speed detect value */
+#define E1000_STATUS_MTXCKOK    0x00000400      /* MTX clock running OK */
+#define E1000_STATUS_PCI66      0x00000800      /* In 66Mhz slot */
+#define E1000_STATUS_BUS64      0x00001000      /* In 64 bit slot */
+#define E1000_STATUS_PCIX_MODE  0x00002000      /* PCI-X mode */
+#define E1000_STATUS_PCIX_SPEED 0x0000C000      /* PCI-X bus speed */
+
+/* Constants used to intrepret the masked PCI-X bus speed. */
+#define E1000_STATUS_PCIX_SPEED_66  0x00000000 /* PCI-X bus speed  50-66 MHz */
+#define E1000_STATUS_PCIX_SPEED_100 0x00004000 /* PCI-X bus speed  66-100 MHz */
+#define E1000_STATUS_PCIX_SPEED_133 0x00008000 /* PCI-X bus speed 100-133 MHz */
+
+/* EEPROM/Flash Control */
+#define E1000_EECD_SK        0x00000001 /* EEPROM Clock */
+#define E1000_EECD_CS        0x00000002 /* EEPROM Chip Select */
+#define E1000_EECD_DI        0x00000004 /* EEPROM Data In */
+#define E1000_EECD_DO        0x00000008 /* EEPROM Data Out */
+#define E1000_EECD_FWE_MASK  0x00000030 
+#define E1000_EECD_FWE_DIS   0x00000010 /* Disable FLASH writes */
+#define E1000_EECD_FWE_EN    0x00000020 /* Enable FLASH writes */
+#define E1000_EECD_FWE_SHIFT 4
+#define E1000_EECD_SIZE      0x00000200 /* EEPROM Size (0=64 word 1=256 word) */
+#define E1000_EECD_REQ       0x00000040 /* EEPROM Access Request */
+#define E1000_EECD_GNT       0x00000080 /* EEPROM Access Grant */
+#define E1000_EECD_PRES      0x00000100 /* EEPROM Present */
+
+/* EEPROM Read */
+#define E1000_EERD_START      0x00000001 /* Start Read */
+#define E1000_EERD_DONE       0x00000010 /* Read Done */
+#define E1000_EERD_ADDR_SHIFT 8
+#define E1000_EERD_ADDR_MASK  0x0000FF00 /* Read Address */
+#define E1000_EERD_DATA_SHIFT 16
+#define E1000_EERD_DATA_MASK  0xFFFF0000 /* Read Data */
+
+/* Extended Device Control */
+#define E1000_CTRL_EXT_GPI0_EN   0x00000001 /* Maps SDP4 to GPI0 */ 
+#define E1000_CTRL_EXT_GPI1_EN   0x00000002 /* Maps SDP5 to GPI1 */
+#define E1000_CTRL_EXT_PHYINT_EN E1000_CTRL_EXT_GPI1_EN
+#define E1000_CTRL_EXT_GPI2_EN   0x00000004 /* Maps SDP6 to GPI2 */
+#define E1000_CTRL_EXT_GPI3_EN   0x00000008 /* Maps SDP7 to GPI3 */
+#define E1000_CTRL_EXT_SDP4_DATA 0x00000010 /* Value of SW Defineable Pin 4 */
+#define E1000_CTRL_EXT_SDP5_DATA 0x00000020 /* Value of SW Defineable Pin 5 */
+#define E1000_CTRL_EXT_PHY_INT   E1000_CTRL_EXT_SDP5_DATA
+#define E1000_CTRL_EXT_SDP6_DATA 0x00000040 /* Value of SW Defineable Pin 6 */
+#define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Defineable Pin 7 */
+#define E1000_CTRL_EXT_SDP4_DIR  0x00000100 /* Direction of SDP4 0=in 1=out */
+#define E1000_CTRL_EXT_SDP5_DIR  0x00000200 /* Direction of SDP5 0=in 1=out */
+#define E1000_CTRL_EXT_SDP6_DIR  0x00000400 /* Direction of SDP6 0=in 1=out */
+#define E1000_CTRL_EXT_SDP7_DIR  0x00000800 /* Direction of SDP7 0=in 1=out */
+#define E1000_CTRL_EXT_ASDCHK    0x00001000 /* Initiate an ASD sequence */
+#define E1000_CTRL_EXT_EE_RST    0x00002000 /* Reinitialize from EEPROM */
+#define E1000_CTRL_EXT_IPS       0x00004000 /* Invert Power State */
+#define E1000_CTRL_EXT_SPD_BYPS  0x00008000 /* Speed Select Bypass */
+#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000
+#define E1000_CTRL_EXT_LINK_MODE_GMII 0x00000000
+#define E1000_CTRL_EXT_LINK_MODE_TBI  0x00C00000
+#define E1000_CTRL_EXT_WR_WMARK_MASK  0x03000000
+#define E1000_CTRL_EXT_WR_WMARK_256   0x00000000
+#define E1000_CTRL_EXT_WR_WMARK_320   0x01000000
+#define E1000_CTRL_EXT_WR_WMARK_384   0x02000000
+#define E1000_CTRL_EXT_WR_WMARK_448   0x03000000
+
+/* MDI Control */
+#define E1000_MDIC_DATA_MASK 0x0000FFFF
+#define E1000_MDIC_REG_MASK  0x001F0000
+#define E1000_MDIC_REG_SHIFT 16
+#define E1000_MDIC_PHY_MASK  0x03E00000
+#define E1000_MDIC_PHY_SHIFT 21
+#define E1000_MDIC_OP_WRITE  0x04000000
+#define E1000_MDIC_OP_READ   0x08000000
+#define E1000_MDIC_READY     0x10000000
+#define E1000_MDIC_INT_EN    0x20000000
+#define E1000_MDIC_ERROR     0x40000000
+
+/* LED Control */
+#define E1000_LEDCTL_LED0_MODE_MASK  0x0000000F
+#define E1000_LEDCTL_LED0_MODE_SHIFT 0
+#define E1000_LEDCTL_LED0_IVRT       0x00000040
+#define E1000_LEDCTL_LED0_BLINK      0x00000080
+#define E1000_LEDCTL_LED1_MODE_MASK  0x00000F00
+#define E1000_LEDCTL_LED1_MODE_SHIFT 8
+#define E1000_LEDCTL_LED1_IVRT       0x00004000
+#define E1000_LEDCTL_LED1_BLINK      0x00008000
+#define E1000_LEDCTL_LED2_MODE_MASK  0x000F0000
+#define E1000_LEDCTL_LED2_MODE_SHIFT 16
+#define E1000_LEDCTL_LED2_IVRT       0x00400000
+#define E1000_LEDCTL_LED2_BLINK      0x00800000
+#define E1000_LEDCTL_LED3_MODE_MASK  0x0F000000
+#define E1000_LEDCTL_LED3_MODE_SHIFT 24
+#define E1000_LEDCTL_LED3_IVRT       0x40000000
+#define E1000_LEDCTL_LED3_BLINK      0x80000000
+
+#define E1000_LEDCTL_MODE_LINK_10_1000  0x0
+#define E1000_LEDCTL_MODE_LINK_100_1000 0x1
+#define E1000_LEDCTL_MODE_LINK_UP       0x2
+#define E1000_LEDCTL_MODE_ACTIVITY      0x3
+#define E1000_LEDCTL_MODE_LINK_ACTIVITY 0x4
+#define E1000_LEDCTL_MODE_LINK_10       0x5
+#define E1000_LEDCTL_MODE_LINK_100      0x6
+#define E1000_LEDCTL_MODE_LINK_1000     0x7
+#define E1000_LEDCTL_MODE_PCIX_MODE     0x8
+#define E1000_LEDCTL_MODE_FULL_DUPLEX   0x9
+#define E1000_LEDCTL_MODE_COLLISION     0xA
+#define E1000_LEDCTL_MODE_BUS_SPEED     0xB
+#define E1000_LEDCTL_MODE_BUS_SIZE      0xC
+#define E1000_LEDCTL_MODE_PAUSED        0xD
+#define E1000_LEDCTL_MODE_LED_ON        0xE
+#define E1000_LEDCTL_MODE_LED_OFF       0xF
+
+/* Receive Address */
+#define E1000_RAH_AV  0x80000000        /* Receive descriptor valid */
+
+/* Interrupt Cause Read */
+#define E1000_ICR_TXDW    0x00000001    /* Transmit desc written back */
+#define E1000_ICR_TXQE    0x00000002    /* Transmit Queue empty */
+#define E1000_ICR_LSC     0x00000004    /* Link Status Change */
+#define E1000_ICR_RXSEQ   0x00000008    /* rx sequence error */
+#define E1000_ICR_RXDMT0  0x00000010    /* rx desc min. threshold (0) */
+#define E1000_ICR_RXO     0x00000040    /* rx overrun */
+#define E1000_ICR_RXT0    0x00000080    /* rx timer intr (ring 0) */
+#define E1000_ICR_MDAC    0x00000200    /* MDIO access complete */
+#define E1000_ICR_RXCFG   0x00000400    /* RX /c/ ordered set */
+#define E1000_ICR_GPI_EN0 0x00000800    /* GP Int 0 */
+#define E1000_ICR_GPI_EN1 0x00001000    /* GP Int 1 */
+#define E1000_ICR_GPI_EN2 0x00002000    /* GP Int 2 */
+#define E1000_ICR_GPI_EN3 0x00004000    /* GP Int 3 */
+#define E1000_ICR_TXD_LOW 0x00008000
+#define E1000_ICR_SRPD    0x00010000
+
+/* Interrupt Cause Set */
+#define E1000_ICS_TXDW    E1000_ICR_TXDW        /* Transmit desc written back */
+#define E1000_ICS_TXQE    E1000_ICR_TXQE        /* Transmit Queue empty */
+#define E1000_ICS_LSC     E1000_ICR_LSC         /* Link Status Change */
+#define E1000_ICS_RXSEQ   E1000_ICR_RXSEQ       /* rx sequence error */
+#define E1000_ICS_RXDMT0  E1000_ICR_RXDMT0      /* rx desc min. threshold */
+#define E1000_ICS_RXO     E1000_ICR_RXO         /* rx overrun */
+#define E1000_ICS_RXT0    E1000_ICR_RXT0        /* rx timer intr */
+#define E1000_ICS_MDAC    E1000_ICR_MDAC        /* MDIO access complete */
+#define E1000_ICS_RXCFG   E1000_ICR_RXCFG       /* RX /c/ ordered set */
+#define E1000_ICS_GPI_EN0 E1000_ICR_GPI_EN0     /* GP Int 0 */
+#define E1000_ICS_GPI_EN1 E1000_ICR_GPI_EN1     /* GP Int 1 */
+#define E1000_ICS_GPI_EN2 E1000_ICR_GPI_EN2     /* GP Int 2 */
+#define E1000_ICS_GPI_EN3 E1000_ICR_GPI_EN3     /* GP Int 3 */
+#define E1000_ICS_TXD_LOW E1000_ICR_TXD_LOW
+#define E1000_ICS_SRPD    E1000_ICR_SRPD
+
+/* Interrupt Mask Set */
+#define E1000_IMS_TXDW    E1000_ICR_TXDW        /* Transmit desc written back */
+#define E1000_IMS_TXQE    E1000_ICR_TXQE        /* Transmit Queue empty */
+#define E1000_IMS_LSC     E1000_ICR_LSC         /* Link Status Change */
+#define E1000_IMS_RXSEQ   E1000_ICR_RXSEQ       /* rx sequence error */
+#define E1000_IMS_RXDMT0  E1000_ICR_RXDMT0      /* rx desc min. threshold */
+#define E1000_IMS_RXO     E1000_ICR_RXO         /* rx overrun */
+#define E1000_IMS_RXT0    E1000_ICR_RXT0        /* rx timer intr */
+#define E1000_IMS_MDAC    E1000_ICR_MDAC        /* MDIO access complete */
+#define E1000_IMS_RXCFG   E1000_ICR_RXCFG       /* RX /c/ ordered set */
+#define E1000_IMS_GPI_EN0 E1000_ICR_GPI_EN0     /* GP Int 0 */
+#define E1000_IMS_GPI_EN1 E1000_ICR_GPI_EN1     /* GP Int 1 */
+#define E1000_IMS_GPI_EN2 E1000_ICR_GPI_EN2     /* GP Int 2 */
+#define E1000_IMS_GPI_EN3 E1000_ICR_GPI_EN3     /* GP Int 3 */
+#define E1000_IMS_TXD_LOW E1000_ICR_TXD_LOW
+#define E1000_IMS_SRPD    E1000_ICR_SRPD
+
+/* Interrupt Mask Clear */
+#define E1000_IMC_TXDW    E1000_ICR_TXDW        /* Transmit desc written back */
+#define E1000_IMC_TXQE    E1000_ICR_TXQE        /* Transmit Queue empty */
+#define E1000_IMC_LSC     E1000_ICR_LSC         /* Link Status Change */
+#define E1000_IMC_RXSEQ   E1000_ICR_RXSEQ       /* rx sequence error */
+#define E1000_IMC_RXDMT0  E1000_ICR_RXDMT0      /* rx desc min. threshold */
+#define E1000_IMC_RXO     E1000_ICR_RXO         /* rx overrun */
+#define E1000_IMC_RXT0    E1000_ICR_RXT0        /* rx timer intr */
+#define E1000_IMC_MDAC    E1000_ICR_MDAC        /* MDIO access complete */
+#define E1000_IMC_RXCFG   E1000_ICR_RXCFG       /* RX /c/ ordered set */
+#define E1000_IMC_GPI_EN0 E1000_ICR_GPI_EN0     /* GP Int 0 */
+#define E1000_IMC_GPI_EN1 E1000_ICR_GPI_EN1     /* GP Int 1 */
+#define E1000_IMC_GPI_EN2 E1000_ICR_GPI_EN2     /* GP Int 2 */
+#define E1000_IMC_GPI_EN3 E1000_ICR_GPI_EN3     /* GP Int 3 */
+#define E1000_IMC_TXD_LOW E1000_ICR_TXD_LOW
+#define E1000_IMC_SRPD    E1000_ICR_SRPD
+
+/* Receive Control */
+#define E1000_RCTL_RST          0x00000001      /* Software reset */
+#define E1000_RCTL_EN           0x00000002      /* enable */
+#define E1000_RCTL_SBP          0x00000004      /* store bad packet */
+#define E1000_RCTL_UPE          0x00000008      /* unicast promiscuous enable */
+#define E1000_RCTL_MPE          0x00000010      /* multicast promiscuous enab */
+#define E1000_RCTL_LPE          0x00000020      /* long packet enable */
+#define E1000_RCTL_LBM_NO       0x00000000      /* no loopback mode */
+#define E1000_RCTL_LBM_MAC      0x00000040      /* MAC loopback mode */
+#define E1000_RCTL_LBM_SLP      0x00000080      /* serial link loopback mode */
+#define E1000_RCTL_LBM_TCVR     0x000000C0      /* tcvr loopback mode */
+#define E1000_RCTL_RDMTS_HALF   0x00000000      /* rx desc min threshold size */
+#define E1000_RCTL_RDMTS_QUAT   0x00000100      /* rx desc min threshold size */
+#define E1000_RCTL_RDMTS_EIGTH  0x00000200      /* rx desc min threshold size */
+#define E1000_RCTL_MO_SHIFT     12              /* multicast offset shift */
+#define E1000_RCTL_MO_0         0x00000000      /* multicast offset 11:0 */
+#define E1000_RCTL_MO_1         0x00001000      /* multicast offset 12:1 */
+#define E1000_RCTL_MO_2         0x00002000      /* multicast offset 13:2 */
+#define E1000_RCTL_MO_3         0x00003000      /* multicast offset 15:4 */
+#define E1000_RCTL_MDR          0x00004000      /* multicast desc ring 0 */
+#define E1000_RCTL_BAM          0x00008000      /* broadcast enable */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */
+#define E1000_RCTL_SZ_2048      0x00000000      /* rx buffer size 2048 */
+#define E1000_RCTL_SZ_1024      0x00010000      /* rx buffer size 1024 */
+#define E1000_RCTL_SZ_512       0x00020000      /* rx buffer size 512 */
+#define E1000_RCTL_SZ_256       0x00030000      /* rx buffer size 256 */
+/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */
+#define E1000_RCTL_SZ_16384     0x00010000      /* rx buffer size 16384 */
+#define E1000_RCTL_SZ_8192      0x00020000      /* rx buffer size 8192 */
+#define E1000_RCTL_SZ_4096      0x00030000      /* rx buffer size 4096 */
+#define E1000_RCTL_VFE          0x00040000      /* vlan filter enable */
+#define E1000_RCTL_CFIEN        0x00080000      /* canonical form enable */
+#define E1000_RCTL_CFI          0x00100000      /* canonical form indicator */
+#define E1000_RCTL_DPF          0x00400000      /* discard pause frames */
+#define E1000_RCTL_PMCF         0x00800000      /* pass MAC control frames */
+#define E1000_RCTL_BSEX         0x02000000      /* Buffer size extension */
+
+/* Receive Descriptor */
+#define E1000_RDT_DELAY 0x0000ffff      /* Delay timer (1=1024us) */
+#define E1000_RDT_FPDB  0x80000000      /* Flush descriptor block */
+#define E1000_RDLEN_LEN 0x0007ff80      /* descriptor length */
+#define E1000_RDH_RDH   0x0000ffff      /* receive descriptor head */
+#define E1000_RDT_RDT   0x0000ffff      /* receive descriptor tail */
+
+/* Flow Control */
+#define E1000_FCRTH_RTH  0x0000FFF8     /* Mask Bits[15:3] for RTH */
+#define E1000_FCRTH_XFCE 0x80000000     /* External Flow Control Enable */
+#define E1000_FCRTL_RTL  0x0000FFF8     /* Mask Bits[15:3] for RTL */
+#define E1000_FCRTL_XONE 0x80000000     /* Enable XON frame transmission */
+
+/* Receive Descriptor Control */
+#define E1000_RXDCTL_PTHRESH 0x0000003F /* RXDCTL Prefetch Threshold */
+#define E1000_RXDCTL_HTHRESH 0x00003F00 /* RXDCTL Host Threshold */
+#define E1000_RXDCTL_WTHRESH 0x003F0000 /* RXDCTL Writeback Threshold */
+#define E1000_RXDCTL_GRAN    0x01000000 /* RXDCTL Granularity */
+
+/* Transmit Descriptor Control */
+#define E1000_TXDCTL_PTHRESH 0x000000FF /* TXDCTL Prefetch Threshold */
+#define E1000_TXDCTL_HTHRESH 0x0000FF00 /* TXDCTL Host Threshold */
+#define E1000_TXDCTL_WTHRESH 0x00FF0000 /* TXDCTL Writeback Threshold */
+#define E1000_TXDCTL_GRAN    0x01000000 /* TXDCTL Granularity */
+#define E1000_TXDCTL_LWTHRESH 0xFE000000 /* TXDCTL Low Threshold */
+#define E1000_TXDCTL_FULL_TX_DESC_WB 0x01010000 /* GRAN=1, WTHRESH=1 */
+
+/* Transmit Configuration Word */
+#define E1000_TXCW_FD         0x00000020        /* TXCW full duplex */
+#define E1000_TXCW_HD         0x00000040        /* TXCW half duplex */
+#define E1000_TXCW_PAUSE      0x00000080        /* TXCW sym pause request */
+#define E1000_TXCW_ASM_DIR    0x00000100        /* TXCW astm pause direction */
+#define E1000_TXCW_PAUSE_MASK 0x00000180        /* TXCW pause request mask */
+#define E1000_TXCW_RF         0x00003000        /* TXCW remote fault */
+#define E1000_TXCW_NP         0x00008000        /* TXCW next page */
+#define E1000_TXCW_CW         0x0000ffff        /* TxConfigWord mask */
+#define E1000_TXCW_TXC        0x40000000        /* Transmit Config control */
+#define E1000_TXCW_ANE        0x80000000        /* Auto-neg enable */
+
+/* Receive Configuration Word */
+#define E1000_RXCW_CW    0x0000ffff     /* RxConfigWord mask */
+#define E1000_RXCW_NC    0x04000000     /* Receive config no carrier */
+#define E1000_RXCW_IV    0x08000000     /* Receive config invalid */
+#define E1000_RXCW_CC    0x10000000     /* Receive config change */
+#define E1000_RXCW_C     0x20000000     /* Receive config */
+#define E1000_RXCW_SYNCH 0x40000000     /* Receive config synch */
+#define E1000_RXCW_ANC   0x80000000     /* Auto-neg complete */
+
+/* Transmit Control */
+#define E1000_TCTL_RST    0x00000001    /* software reset */
+#define E1000_TCTL_EN     0x00000002    /* enable tx */
+#define E1000_TCTL_BCE    0x00000004    /* busy check enable */
+#define E1000_TCTL_PSP    0x00000008    /* pad short packets */
+#define E1000_TCTL_CT     0x00000ff0    /* collision threshold */
+#define E1000_TCTL_COLD   0x003ff000    /* collision distance */
+#define E1000_TCTL_SWXOFF 0x00400000    /* SW Xoff transmission */
+#define E1000_TCTL_PBE    0x00800000    /* Packet Burst Enable */
+#define E1000_TCTL_RTLC   0x01000000    /* Re-transmit on late collision */
+#define E1000_TCTL_NRTU   0x02000000    /* No Re-transmit on underrun */
+
+/* Receive Checksum Control */
+#define E1000_RXCSUM_PCSS_MASK 0x000000FF   /* Packet Checksum Start */
+#define E1000_RXCSUM_IPOFL     0x00000100   /* IPv4 checksum offload */
+#define E1000_RXCSUM_TUOFL     0x00000200   /* TCP / UDP checksum offload */
+#define E1000_RXCSUM_IPV6OFL   0x00000400   /* IPv6 checksum offload */
+
+/* Definitions for power management and wakeup registers */
+/* Wake Up Control */
+#define E1000_WUC_APME       0x00000001 /* APM Enable */
+#define E1000_WUC_PME_EN     0x00000002 /* PME Enable */
+#define E1000_WUC_PME_STATUS 0x00000004 /* PME Status */
+#define E1000_WUC_APMPME     0x00000008 /* Assert PME on APM Wakeup */
+
+/* Wake Up Filter Control */
+#define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
+#define E1000_WUFC_MAG  0x00000002 /* Magic Packet Wakeup Enable */
+#define E1000_WUFC_EX   0x00000004 /* Directed Exact Wakeup Enable */
+#define E1000_WUFC_MC   0x00000008 /* Directed Multicast Wakeup Enable */
+#define E1000_WUFC_BC   0x00000010 /* Broadcast Wakeup Enable */
+#define E1000_WUFC_ARP  0x00000020 /* ARP Request Packet Wakeup Enable */
+#define E1000_WUFC_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Enable */
+#define E1000_WUFC_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Enable */
+#define E1000_WUFC_FLX0 0x00010000 /* Flexible Filter 0 Enable */
+#define E1000_WUFC_FLX1 0x00020000 /* Flexible Filter 1 Enable */
+#define E1000_WUFC_FLX2 0x00040000 /* Flexible Filter 2 Enable */
+#define E1000_WUFC_FLX3 0x00080000 /* Flexible Filter 3 Enable */
+#define E1000_WUFC_ALL_FILTERS 0x000F00FF /* Mask for all wakeup filters */
+#define E1000_WUFC_FLX_OFFSET 16       /* Offset to the Flexible Filters bits */
+#define E1000_WUFC_FLX_FILTERS 0x000F0000 /* Mask for the 4 flexible filters */
+
+/* Wake Up Status */
+#define E1000_WUS_LNKC 0x00000001 /* Link Status Changed */
+#define E1000_WUS_MAG  0x00000002 /* Magic Packet Received */
+#define E1000_WUS_EX   0x00000004 /* Directed Exact Received */
+#define E1000_WUS_MC   0x00000008 /* Directed Multicast Received */
+#define E1000_WUS_BC   0x00000010 /* Broadcast Received */
+#define E1000_WUS_ARP  0x00000020 /* ARP Request Packet Received */
+#define E1000_WUS_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Received */
+#define E1000_WUS_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Received */
+#define E1000_WUS_FLX0 0x00010000 /* Flexible Filter 0 Match */
+#define E1000_WUS_FLX1 0x00020000 /* Flexible Filter 1 Match */
+#define E1000_WUS_FLX2 0x00040000 /* Flexible Filter 2 Match */
+#define E1000_WUS_FLX3 0x00080000 /* Flexible Filter 3 Match */
+#define E1000_WUS_FLX_FILTERS 0x000F0000 /* Mask for the 4 flexible filters */
+
+/* Management Control */
+#define E1000_MANC_SMBUS_EN      0x00000001 /* SMBus Enabled - RO */
+#define E1000_MANC_ASF_EN        0x00000002 /* ASF Enabled - RO */
+#define E1000_MANC_R_ON_FORCE    0x00000004 /* Reset on Force TCO - RO */
+#define E1000_MANC_RMCP_EN       0x00000100 /* Enable RCMP 026Fh Filtering */
+#define E1000_MANC_0298_EN       0x00000200 /* Enable RCMP 0298h Filtering */
+#define E1000_MANC_IPV4_EN       0x00000400 /* Enable IPv4 */
+#define E1000_MANC_IPV6_EN       0x00000800 /* Enable IPv6 */
+#define E1000_MANC_SNAP_EN       0x00001000 /* Accept LLC/SNAP */
+#define E1000_MANC_ARP_EN        0x00002000 /* Enable ARP Request Filtering */
+#define E1000_MANC_NEIGHBOR_EN   0x00004000 /* Enable Neighbor Discovery 
+                                             * Filtering */
+#define E1000_MANC_TCO_RESET     0x00010000 /* TCO Reset Occurred */
+#define E1000_MANC_RCV_TCO_EN    0x00020000 /* Receive TCO Packets Enabled */
+#define E1000_MANC_REPORT_STATUS 0x00040000 /* Status Reporting Enabled */
+#define E1000_MANC_SMB_REQ       0x01000000 /* SMBus Request */
+#define E1000_MANC_SMB_GNT       0x02000000 /* SMBus Grant */
+#define E1000_MANC_SMB_CLK_IN    0x04000000 /* SMBus Clock In */
+#define E1000_MANC_SMB_DATA_IN   0x08000000 /* SMBus Data In */
+#define E1000_MANC_SMB_DATA_OUT  0x10000000 /* SMBus Data Out */
+#define E1000_MANC_SMB_CLK_OUT   0x20000000 /* SMBus Clock Out */
+
+#define E1000_MANC_SMB_DATA_OUT_SHIFT  28 /* SMBus Data Out Shift */
+#define E1000_MANC_SMB_CLK_OUT_SHIFT   29 /* SMBus Clock Out Shift */
+
+/* Wake Up Packet Length */
+#define E1000_WUPL_LENGTH_MASK 0x0FFF   /* Only the lower 12 bits are valid */
+
+#define E1000_MDALIGN          4096
+
+/* EEPROM Commands */
+#define EEPROM_READ_OPCODE  0x6  /* EERPOM read opcode */
+#define EEPROM_WRITE_OPCODE 0x5  /* EERPOM write opcode */
+#define EEPROM_ERASE_OPCODE 0x7  /* EERPOM erase opcode */
+#define EEPROM_EWEN_OPCODE  0x13 /* EERPOM erase/write enable */
+#define EEPROM_EWDS_OPCODE  0x10 /* EERPOM erast/write disable */
+
+/* EEPROM Word Offsets */
+#define EEPROM_COMPAT              0x0003
+#define EEPROM_ID_LED_SETTINGS     0x0004
+#define EEPROM_INIT_CONTROL1_REG   0x000A
+#define EEPROM_INIT_CONTROL2_REG   0x000F
+#define EEPROM_FLASH_VERSION       0x0032
+#define EEPROM_CHECKSUM_REG        0x003F
+
+/* Word definitions for ID LED Settings */
+#define ID_LED_RESERVED_0000 0x0000
+#define ID_LED_RESERVED_FFFF 0xFFFF
+#define ID_LED_DEFAULT       ((ID_LED_OFF1_ON2 << 12) | \
+                              (ID_LED_OFF1_OFF2 << 8) | \
+                              (ID_LED_DEF1_DEF2 << 4) | \
+                              (ID_LED_DEF1_DEF2))
+#define ID_LED_DEF1_DEF2     0x1
+#define ID_LED_DEF1_ON2      0x2
+#define ID_LED_DEF1_OFF2     0x3
+#define ID_LED_ON1_DEF2      0x4
+#define ID_LED_ON1_ON2       0x5
+#define ID_LED_ON1_OFF2      0x6
+#define ID_LED_OFF1_DEF2     0x7
+#define ID_LED_OFF1_ON2      0x8
+#define ID_LED_OFF1_OFF2     0x9
+
+/* Mask bits for fields in Word 0x03 of the EEPROM */
+#define EEPROM_COMPAT_SERVER 0x0400
+#define EEPROM_COMPAT_CLIENT 0x0200
+
+/* Mask bits for fields in Word 0x0a of the EEPROM */
+#define EEPROM_WORD0A_ILOS   0x0010
+#define EEPROM_WORD0A_SWDPIO 0x01E0
+#define EEPROM_WORD0A_LRST   0x0200
+#define EEPROM_WORD0A_FD     0x0400
+#define EEPROM_WORD0A_66MHZ  0x0800
+
+/* Mask bits for fields in Word 0x0f of the EEPROM */
+#define EEPROM_WORD0F_PAUSE_MASK 0x3000
+#define EEPROM_WORD0F_PAUSE      0x1000
+#define EEPROM_WORD0F_ASM_DIR    0x2000
+#define EEPROM_WORD0F_ANE        0x0800
+#define EEPROM_WORD0F_SWPDIO_EXT 0x00F0
+
+/* For checksumming, the sum of all words in the EEPROM should equal 0xBABA. */
+#define EEPROM_SUM 0xBABA
+
+/* EEPROM Map defines (WORD OFFSETS)*/
+#define EEPROM_NODE_ADDRESS_BYTE_0 0
+#define EEPROM_PBA_BYTE_1          8
+
+/* EEPROM Map Sizes (Byte Counts) */
+#define PBA_SIZE 4
+
+/* Collision related configuration parameters */
+#define E1000_COLLISION_THRESHOLD       16
+#define E1000_CT_SHIFT                  4
+#define E1000_COLLISION_DISTANCE        64
+#define E1000_FDX_COLLISION_DISTANCE    E1000_COLLISION_DISTANCE
+#define E1000_HDX_COLLISION_DISTANCE    E1000_COLLISION_DISTANCE
+#define E1000_GB_HDX_COLLISION_DISTANCE 512
+#define E1000_COLD_SHIFT                12
+
+/* The number of Transmit and Receive Descriptors must be a multiple of 8 */
+#define REQ_TX_DESCRIPTOR_MULTIPLE  8
+#define REQ_RX_DESCRIPTOR_MULTIPLE  8
+
+/* Default values for the transmit IPG register */
+#define DEFAULT_82542_TIPG_IPGT        10
+#define DEFAULT_82543_TIPG_IPGT_FIBER  9
+#define DEFAULT_82543_TIPG_IPGT_COPPER 8
+
+#define E1000_TIPG_IPGT_MASK  0x000003FF
+#define E1000_TIPG_IPGR1_MASK 0x000FFC00
+#define E1000_TIPG_IPGR2_MASK 0x3FF00000
+
+#define DEFAULT_82542_TIPG_IPGR1 2
+#define DEFAULT_82543_TIPG_IPGR1 8
+#define E1000_TIPG_IPGR1_SHIFT  10
+
+#define DEFAULT_82542_TIPG_IPGR2 10
+#define DEFAULT_82543_TIPG_IPGR2 6
+#define E1000_TIPG_IPGR2_SHIFT  20
+
+#define E1000_TXDMAC_DPP 0x00000001
+
+/* Adaptive IFS defines */
+#define TX_THRESHOLD_START     8
+#define TX_THRESHOLD_INCREMENT 10
+#define TX_THRESHOLD_DECREMENT 1
+#define TX_THRESHOLD_STOP      190
+#define TX_THRESHOLD_DISABLE   0
+#define TX_THRESHOLD_TIMER_MS  10000
+#define MIN_NUM_XMITS          1000
+#define IFS_MAX                80
+#define IFS_STEP               10
+#define IFS_MIN                40
+#define IFS_RATIO              4
+
+/* PBA constants */
+#define E1000_PBA_16K 0x0010    /* 16KB, default TX allocation */
+#define E1000_PBA_24K 0x0018
+#define E1000_PBA_40K 0x0028
+#define E1000_PBA_48K 0x0030    /* 48KB, default RX allocation */
+
+/* Flow Control Constants */
+#define FLOW_CONTROL_ADDRESS_LOW  0x00C28001
+#define FLOW_CONTROL_ADDRESS_HIGH 0x00000100
+#define FLOW_CONTROL_TYPE         0x8808
+
+/* The historical defaults for the flow control values are given below. */
+#define FC_DEFAULT_HI_THRESH        (0x8000)    /* 32KB */
+#define FC_DEFAULT_LO_THRESH        (0x4000)    /* 16KB */
+#define FC_DEFAULT_TX_TIMER         (0x100)     /* ~130 us */
+
+/* PCIX Config space */
+#define PCIX_COMMAND_REGISTER    0xE6
+#define PCIX_STATUS_REGISTER_LO  0xE8
+#define PCIX_STATUS_REGISTER_HI  0xEA
+
+#define PCIX_COMMAND_MMRBC_MASK      0x000C
+#define PCIX_COMMAND_MMRBC_SHIFT     0x2
+#define PCIX_STATUS_HI_MMRBC_MASK    0x0060
+#define PCIX_STATUS_HI_MMRBC_SHIFT   0x5
+#define PCIX_STATUS_HI_MMRBC_4K      0x3
+#define PCIX_STATUS_HI_MMRBC_2K      0x2
+
+
+/* The number of bits that we need to shift right to move the "pause"
+ * bits from the EEPROM (bits 13:12) to the "pause" (bits 8:7) field
+ * in the TXCW register 
+ */
+#define PAUSE_SHIFT 5
+
+/* The number of bits that we need to shift left to move the "SWDPIO"
+ * bits from the EEPROM (bits 8:5) to the "SWDPIO" (bits 25:22) field
+ * in the CTRL register 
+ */
+#define SWDPIO_SHIFT 17
+
+/* The number of bits that we need to shift left to move the "SWDPIO_EXT"
+ * bits from the EEPROM word F (bits 7:4) to the bits 11:8 of The
+ * Extended CTRL register.
+ * in the CTRL register 
+ */
+#define SWDPIO__EXT_SHIFT 4
+
+/* The number of bits that we need to shift left to move the "ILOS"
+ * bit from the EEPROM (bit 4) to the "ILOS" (bit 7) field
+ * in the CTRL register 
+ */
+#define ILOS_SHIFT  3
+
+
+#define RECEIVE_BUFFER_ALIGN_SIZE  (256)
+
+/* The number of milliseconds we wait for auto-negotiation to complete */
+#define LINK_UP_TIMEOUT             500
+
+#define E1000_TX_BUFFER_SIZE ((uint32_t)1514)
+
+/* The carrier extension symbol, as received by the NIC. */
+#define CARRIER_EXTENSION   0x0F
+
+/* TBI_ACCEPT macro definition:
+ *
+ * This macro requires:
+ *      adapter = a pointer to struct e1000_hw 
+ *      status = the 8 bit status field of the RX descriptor with EOP set
+ *      error = the 8 bit error field of the RX descriptor with EOP set
+ *      length = the sum of all the length fields of the RX descriptors that
+ *               make up the current frame
+ *      last_byte = the last byte of the frame DMAed by the hardware
+ *      max_frame_length = the maximum frame length we want to accept.
+ *      min_frame_length = the minimum frame length we want to accept.
+ *
+ * This macro is a conditional that should be used in the interrupt 
+ * handler's Rx processing routine when RxErrors have been detected.
+ *
+ * Typical use:
+ *  ...
+ *  if (TBI_ACCEPT) {
+ *      accept_frame = TRUE;
+ *      e1000_tbi_adjust_stats(adapter, MacAddress);
+ *      frame_length--;
+ *  } else {
+ *      accept_frame = FALSE;
+ *  }
+ *  ...
+ */
+
+#define TBI_ACCEPT(adapter, status, errors, length, last_byte) \
+    ((adapter)->tbi_compatibility_on && \
+     (((errors) & E1000_RXD_ERR_FRAME_ERR_MASK) == E1000_RXD_ERR_CE) && \
+     ((last_byte) == CARRIER_EXTENSION) && \
+     (((status) & E1000_RXD_STAT_VP) ? \
+          (((length) > ((adapter)->min_frame_size - VLAN_TAG_SIZE)) && \
+           ((length) <= ((adapter)->max_frame_size + 1))) : \
+          (((length) > (adapter)->min_frame_size) && \
+           ((length) <= ((adapter)->max_frame_size + VLAN_TAG_SIZE + 1)))))
+
+
+/* Structures, enums, and macros for the PHY */
+
+/* Bit definitions for the Management Data IO (MDIO) and Management Data
+ * Clock (MDC) pins in the Device Control Register.
+ */
+#define E1000_CTRL_PHY_RESET_DIR  E1000_CTRL_SWDPIO0
+#define E1000_CTRL_PHY_RESET      E1000_CTRL_SWDPIN0
+#define E1000_CTRL_MDIO_DIR       E1000_CTRL_SWDPIO2
+#define E1000_CTRL_MDIO           E1000_CTRL_SWDPIN2
+#define E1000_CTRL_MDC_DIR        E1000_CTRL_SWDPIO3
+#define E1000_CTRL_MDC            E1000_CTRL_SWDPIN3
+#define E1000_CTRL_PHY_RESET_DIR4 E1000_CTRL_EXT_SDP4_DIR
+#define E1000_CTRL_PHY_RESET4     E1000_CTRL_EXT_SDP4_DATA
+
+/* PHY 1000 MII Register/Bit Definitions */
+/* PHY Registers defined by IEEE */
+#define PHY_CTRL         0x00 /* Control Register */
+#define PHY_STATUS       0x01 /* Status Regiser */
+#define PHY_ID1          0x02 /* Phy Id Reg (word 1) */
+#define PHY_ID2          0x03 /* Phy Id Reg (word 2) */
+#define PHY_AUTONEG_ADV  0x04 /* Autoneg Advertisement */
+#define PHY_LP_ABILITY   0x05 /* Link Partner Ability (Base Page) */
+#define PHY_AUTONEG_EXP  0x06 /* Autoneg Expansion Reg */
+#define PHY_NEXT_PAGE_TX 0x07 /* Next Page TX */
+#define PHY_LP_NEXT_PAGE 0x08 /* Link Partner Next Page */
+#define PHY_1000T_CTRL   0x09 /* 1000Base-T Control Reg */
+#define PHY_1000T_STATUS 0x0A /* 1000Base-T Status Reg */
+#define PHY_EXT_STATUS   0x0F /* Extended Status Reg */
+
+/* M88E1000 Specific Registers */
+#define M88E1000_PHY_SPEC_CTRL     0x10  /* PHY Specific Control Register */
+#define M88E1000_PHY_SPEC_STATUS   0x11  /* PHY Specific Status Register */
+#define M88E1000_INT_ENABLE        0x12  /* Interrupt Enable Register */
+#define M88E1000_INT_STATUS        0x13  /* Interrupt Status Register */
+#define M88E1000_EXT_PHY_SPEC_CTRL 0x14  /* Extended PHY Specific Control */
+#define M88E1000_RX_ERR_CNTR       0x15  /* Receive Error Counter */
+
+#define MAX_PHY_REG_ADDRESS 0x1F        /* 5 bit address bus (0-0x1F) */
+
+/* PHY Control Register */
+#define MII_CR_SPEED_SELECT_MSB 0x0040  /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_COLL_TEST_ENABLE 0x0080  /* Collision test enable */
+#define MII_CR_FULL_DUPLEX      0x0100  /* FDX =1, half duplex =0 */
+#define MII_CR_RESTART_AUTO_NEG 0x0200  /* Restart auto negotiation */
+#define MII_CR_ISOLATE          0x0400  /* Isolate PHY from MII */
+#define MII_CR_POWER_DOWN       0x0800  /* Power down */
+#define MII_CR_AUTO_NEG_EN      0x1000  /* Auto Neg Enable */
+#define MII_CR_SPEED_SELECT_LSB 0x2000  /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define MII_CR_LOOPBACK         0x4000  /* 0 = normal, 1 = loopback */
+#define MII_CR_RESET            0x8000  /* 0 = normal, 1 = PHY reset */
+
+/* PHY Status Register */
+#define MII_SR_EXTENDED_CAPS     0x0001 /* Extended register capabilities */
+#define MII_SR_JABBER_DETECT     0x0002 /* Jabber Detected */
+#define MII_SR_LINK_STATUS       0x0004 /* Link Status 1 = link */
+#define MII_SR_AUTONEG_CAPS      0x0008 /* Auto Neg Capable */
+#define MII_SR_REMOTE_FAULT      0x0010 /* Remote Fault Detect */
+#define MII_SR_AUTONEG_COMPLETE  0x0020 /* Auto Neg Complete */
+#define MII_SR_PREAMBLE_SUPPRESS 0x0040 /* Preamble may be suppressed */
+#define MII_SR_EXTENDED_STATUS   0x0100 /* Ext. status info in Reg 0x0F */
+#define MII_SR_100T2_HD_CAPS     0x0200 /* 100T2 Half Duplex Capable */
+#define MII_SR_100T2_FD_CAPS     0x0400 /* 100T2 Full Duplex Capable */
+#define MII_SR_10T_HD_CAPS       0x0800 /* 10T   Half Duplex Capable */
+#define MII_SR_10T_FD_CAPS       0x1000 /* 10T   Full Duplex Capable */
+#define MII_SR_100X_HD_CAPS      0x2000 /* 100X  Half Duplex Capable */
+#define MII_SR_100X_FD_CAPS      0x4000 /* 100X  Full Duplex Capable */
+#define MII_SR_100T4_CAPS        0x8000 /* 100T4 Capable */
+
+/* Autoneg Advertisement Register */
+#define NWAY_AR_SELECTOR_FIELD 0x0001   /* indicates IEEE 802.3 CSMA/CD */
+#define NWAY_AR_10T_HD_CAPS    0x0020   /* 10T   Half Duplex Capable */
+#define NWAY_AR_10T_FD_CAPS    0x0040   /* 10T   Full Duplex Capable */
+#define NWAY_AR_100TX_HD_CAPS  0x0080   /* 100TX Half Duplex Capable */
+#define NWAY_AR_100TX_FD_CAPS  0x0100   /* 100TX Full Duplex Capable */
+#define NWAY_AR_100T4_CAPS     0x0200   /* 100T4 Capable */
+#define NWAY_AR_PAUSE          0x0400   /* Pause operation desired */
+#define NWAY_AR_ASM_DIR        0x0800   /* Asymmetric Pause Direction bit */
+#define NWAY_AR_REMOTE_FAULT   0x2000   /* Remote Fault detected */
+#define NWAY_AR_NEXT_PAGE      0x8000   /* Next Page ability supported */
+
+/* Link Partner Ability Register (Base Page) */
+#define NWAY_LPAR_SELECTOR_FIELD 0x0000 /* LP protocol selector field */
+#define NWAY_LPAR_10T_HD_CAPS    0x0020 /* LP is 10T   Half Duplex Capable */
+#define NWAY_LPAR_10T_FD_CAPS    0x0040 /* LP is 10T   Full Duplex Capable */
+#define NWAY_LPAR_100TX_HD_CAPS  0x0080 /* LP is 100TX Half Duplex Capable */
+#define NWAY_LPAR_100TX_FD_CAPS  0x0100 /* LP is 100TX Full Duplex Capable */
+#define NWAY_LPAR_100T4_CAPS     0x0200 /* LP is 100T4 Capable */
+#define NWAY_LPAR_PAUSE          0x0400 /* LP Pause operation desired */
+#define NWAY_LPAR_ASM_DIR        0x0800 /* LP Asymmetric Pause Direction bit */
+#define NWAY_LPAR_REMOTE_FAULT   0x2000 /* LP has detected Remote Fault */
+#define NWAY_LPAR_ACKNOWLEDGE    0x4000 /* LP has rx'd link code word */
+#define NWAY_LPAR_NEXT_PAGE      0x8000 /* Next Page ability supported */
+
+/* Autoneg Expansion Register */
+#define NWAY_ER_LP_NWAY_CAPS      0x0001 /* LP has Auto Neg Capability */
+#define NWAY_ER_PAGE_RXD          0x0002 /* LP is 10T   Half Duplex Capable */
+#define NWAY_ER_NEXT_PAGE_CAPS    0x0004 /* LP is 10T   Full Duplex Capable */
+#define NWAY_ER_LP_NEXT_PAGE_CAPS 0x0008 /* LP is 100TX Half Duplex Capable */
+#define NWAY_ER_PAR_DETECT_FAULT  0x0100 /* LP is 100TX Full Duplex Capable */
+
+/* Next Page TX Register */
+#define NPTX_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */
+#define NPTX_TOGGLE         0x0800 /* Toggles between exchanges
+                                    * of different NP
+                                    */
+#define NPTX_ACKNOWLDGE2    0x1000 /* 1 = will comply with msg
+                                    * 0 = cannot comply with msg
+                                    */
+#define NPTX_MSG_PAGE       0x2000 /* formatted(1)/unformatted(0) pg */
+#define NPTX_NEXT_PAGE      0x8000 /* 1 = addition NP will follow 
+                                    * 0 = sending last NP
+                                    */
+
+/* Link Partner Next Page Register */
+#define LP_RNPR_MSG_CODE_FIELD 0x0001 /* NP msg code or unformatted data */
+#define LP_RNPR_TOGGLE         0x0800 /* Toggles between exchanges
+                                       * of different NP
+                                       */
+#define LP_RNPR_ACKNOWLDGE2    0x1000 /* 1 = will comply with msg 
+                                       * 0 = cannot comply with msg
+                                       */
+#define LP_RNPR_MSG_PAGE       0x2000  /* formatted(1)/unformatted(0) pg */
+#define LP_RNPR_ACKNOWLDGE     0x4000  /* 1 = ACK / 0 = NO ACK */
+#define LP_RNPR_NEXT_PAGE      0x8000  /* 1 = addition NP will follow
+                                        * 0 = sending last NP 
+                                        */
+
+/* 1000BASE-T Control Register */
+#define CR_1000T_ASYM_PAUSE      0x0080 /* Advertise asymmetric pause bit */
+#define CR_1000T_HD_CAPS         0x0100 /* Advertise 1000T HD capability */
+#define CR_1000T_FD_CAPS         0x0200 /* Advertise 1000T FD capability  */
+#define CR_1000T_REPEATER_DTE    0x0400 /* 1=Repeater/switch device port */
+                                        /* 0=DTE device */
+#define CR_1000T_MS_VALUE        0x0800 /* 1=Configure PHY as Master */
+                                        /* 0=Configure PHY as Slave */
+#define CR_1000T_MS_ENABLE       0x1000 /* 1=Master/Slave manual config value */
+                                        /* 0=Automatic Master/Slave config */
+#define CR_1000T_TEST_MODE_NORMAL 0x0000 /* Normal Operation */
+#define CR_1000T_TEST_MODE_1     0x2000 /* Transmit Waveform test */
+#define CR_1000T_TEST_MODE_2     0x4000 /* Master Transmit Jitter test */
+#define CR_1000T_TEST_MODE_3     0x6000 /* Slave Transmit Jitter test */
+#define CR_1000T_TEST_MODE_4     0x8000 /* Transmitter Distortion test */
+
+/* 1000BASE-T Status Register */
+#define SR_1000T_IDLE_ERROR_CNT   0x00FF /* Num idle errors since last read */
+#define SR_1000T_ASYM_PAUSE_DIR   0x0100 /* LP asymmetric pause direction bit */
+#define SR_1000T_LP_HD_CAPS       0x0400 /* LP is 1000T HD capable */
+#define SR_1000T_LP_FD_CAPS       0x0800 /* LP is 1000T FD capable */
+#define SR_1000T_REMOTE_RX_STATUS 0x1000 /* Remote receiver OK */
+#define SR_1000T_LOCAL_RX_STATUS  0x2000 /* Local receiver OK */
+#define SR_1000T_MS_CONFIG_RES    0x4000 /* 1=Local TX is Master, 0=Slave */
+#define SR_1000T_MS_CONFIG_FAULT  0x8000 /* Master/Slave config fault */
+#define SR_1000T_REMOTE_RX_STATUS_SHIFT 12
+#define SR_1000T_LOCAL_RX_STATUS_SHIFT  13
+
+/* Extended Status Register */
+#define IEEE_ESR_1000T_HD_CAPS 0x1000 /* 1000T HD capable */
+#define IEEE_ESR_1000T_FD_CAPS 0x2000 /* 1000T FD capable */
+#define IEEE_ESR_1000X_HD_CAPS 0x4000 /* 1000X HD capable */
+#define IEEE_ESR_1000X_FD_CAPS 0x8000 /* 1000X FD capable */
+
+#define PHY_TX_POLARITY_MASK   0x0100 /* register 10h bit 8 (polarity bit) */
+#define PHY_TX_NORMAL_POLARITY 0      /* register 10h bit 8 (normal polarity) */
+
+#define AUTO_POLARITY_DISABLE  0x0010 /* register 11h bit 4 */
+                                      /* (0=enable, 1=disable) */
+
+/* M88E1000 PHY Specific Control Register */
+#define M88E1000_PSCR_JABBER_DISABLE    0x0001 /* 1=Jabber Function disabled */
+#define M88E1000_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */
+#define M88E1000_PSCR_SQE_TEST          0x0004 /* 1=SQE Test enabled */
+#define M88E1000_PSCR_CLK125_DISABLE    0x0010 /* 1=CLK125 low, 
+                                                * 0=CLK125 toggling
+                                                */
+#define M88E1000_PSCR_MDI_MANUAL_MODE  0x0000  /* MDI Crossover Mode bits 6:5 */
+                                               /* Manual MDI configuration */
+#define M88E1000_PSCR_MDIX_MANUAL_MODE 0x0020  /* Manual MDIX configuration */
+#define M88E1000_PSCR_AUTO_X_1000T     0x0040  /* 1000BASE-T: Auto crossover,
+                                                *  100BASE-TX/10BASE-T: 
+                                                *  MDI Mode
+                                                */
+#define M88E1000_PSCR_AUTO_X_MODE      0x0060  /* Auto crossover enabled 
+                                                * all speeds. 
+                                                */
+#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE 0x0080 
+                                        /* 1=Enable Extended 10BASE-T distance
+                                         * (Lower 10BASE-T RX Threshold)
+                                         * 0=Normal 10BASE-T RX Threshold */
+#define M88E1000_PSCR_MII_5BIT_ENABLE      0x0100
+                                        /* 1=5-Bit interface in 100BASE-TX
+                                         * 0=MII interface in 100BASE-TX */
+#define M88E1000_PSCR_SCRAMBLER_DISABLE    0x0200 /* 1=Scrambler disable */
+#define M88E1000_PSCR_FORCE_LINK_GOOD      0x0400 /* 1=Force link good */
+#define M88E1000_PSCR_ASSERT_CRS_ON_TX     0x0800 /* 1=Assert CRS on Transmit */
+
+#define M88E1000_PSCR_POLARITY_REVERSAL_SHIFT    1
+#define M88E1000_PSCR_AUTO_X_MODE_SHIFT          5
+#define M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT 7
+
+/* M88E1000 PHY Specific Status Register */
+#define M88E1000_PSSR_JABBER             0x0001 /* 1=Jabber */
+#define M88E1000_PSSR_REV_POLARITY       0x0002 /* 1=Polarity reversed */
+#define M88E1000_PSSR_MDIX               0x0040 /* 1=MDIX; 0=MDI */
+#define M88E1000_PSSR_CABLE_LENGTH       0x0380 /* 0=<50M;1=50-80M;2=80-110M;
+                                            * 3=110-140M;4=>140M */
+#define M88E1000_PSSR_LINK               0x0400 /* 1=Link up, 0=Link down */
+#define M88E1000_PSSR_SPD_DPLX_RESOLVED  0x0800 /* 1=Speed & Duplex resolved */
+#define M88E1000_PSSR_PAGE_RCVD          0x1000 /* 1=Page received */
+#define M88E1000_PSSR_DPLX               0x2000 /* 1=Duplex 0=Half Duplex */
+#define M88E1000_PSSR_SPEED              0xC000 /* Speed, bits 14:15 */
+#define M88E1000_PSSR_10MBS              0x0000 /* 00=10Mbs */
+#define M88E1000_PSSR_100MBS             0x4000 /* 01=100Mbs */
+#define M88E1000_PSSR_1000MBS            0x8000 /* 10=1000Mbs */
+
+#define M88E1000_PSSR_REV_POLARITY_SHIFT 1
+#define M88E1000_PSSR_MDIX_SHIFT         6
+#define M88E1000_PSSR_CABLE_LENGTH_SHIFT 7
+
+/* M88E1000 Extended PHY Specific Control Register */
+#define M88E1000_EPSCR_FIBER_LOOPBACK 0x4000 /* 1=Fiber loopback */
+#define M88E1000_EPSCR_DOWN_NO_IDLE   0x8000 /* 1=Lost lock detect enabled.
+                                              * Will assert lost lock and bring
+                                              * link down if idle not seen
+                                              * within 1ms in 1000BASE-T 
+                                              */
+/* Number of times we will attempt to autonegotiate before downshifting if we
+ * are the master */
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK 0x0C00
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_1X   0x0000    
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_2X   0x0400
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_3X   0x0800
+#define M88E1000_EPSCR_MASTER_DOWNSHIFT_4X   0x0C00
+/* Number of times we will attempt to autonegotiate before downshifting if we
+ * are the slave */
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK  0x0300
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_DIS   0x0000
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X    0x0100
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_2X    0x0200
+#define M88E1000_EPSCR_SLAVE_DOWNSHIFT_3X    0x0300
+#define M88E1000_EPSCR_TX_CLK_2_5     0x0060 /* 2.5 MHz TX_CLK */
+#define M88E1000_EPSCR_TX_CLK_25      0x0070 /* 25  MHz TX_CLK */
+#define M88E1000_EPSCR_TX_CLK_0       0x0000 /* NO  TX_CLK */
+
+/* Bit definitions for valid PHY IDs. */
+#define M88E1000_E_PHY_ID  0x01410C50
+#define M88E1000_I_PHY_ID  0x01410C30
+#define M88E1011_I_PHY_ID  0x01410C20
+#define M88E1000_12_PHY_ID M88E1000_E_PHY_ID
+#define M88E1000_14_PHY_ID M88E1000_E_PHY_ID
+#define M88E1011_I_REV_4   0x04
+
+/* Miscellaneous PHY bit definitions. */
+#define PHY_PREAMBLE        0xFFFFFFFF
+#define PHY_SOF             0x01
+#define PHY_OP_READ         0x02
+#define PHY_OP_WRITE        0x01
+#define PHY_TURNAROUND      0x02
+#define PHY_PREAMBLE_SIZE   32
+#define MII_CR_SPEED_1000   0x0040
+#define MII_CR_SPEED_100    0x2000
+#define MII_CR_SPEED_10     0x0000
+#define E1000_PHY_ADDRESS   0x01
+#define PHY_AUTO_NEG_TIME   45  /* 4.5 Seconds */
+#define PHY_FORCE_TIME      20  /* 2.0 Seconds */
+#define PHY_REVISION_MASK   0xFFFFFFF0
+#define DEVICE_SPEED_MASK   0x00000300  /* Device Ctrl Reg Speed Mask */
+#define REG4_SPEED_MASK     0x01E0
+#define REG9_SPEED_MASK     0x0300
+#define ADVERTISE_10_HALF   0x0001
+#define ADVERTISE_10_FULL   0x0002
+#define ADVERTISE_100_HALF  0x0004
+#define ADVERTISE_100_FULL  0x0008
+#define ADVERTISE_1000_HALF 0x0010
+#define ADVERTISE_1000_FULL 0x0020
+#define AUTONEG_ADVERTISE_SPEED_DEFAULT 0x002F  /* Everything but 1000-Half */
+
+#endif /* _E1000_HW_H_ */
diff --git a/xen-2.4.16/drivers/net/e1000/e1000_main.c b/xen-2.4.16/drivers/net/e1000/e1000_main.c
new file mode 100644 (file)
index 0000000..3d4556b
--- /dev/null
@@ -0,0 +1,2281 @@
+/*******************************************************************************
+
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  This program is free software; you can redistribute it and/or modify it 
+  under the terms of the GNU General Public License as published by the Free 
+  Software Foundation; either version 2 of the License, or (at your option) 
+  any later version.
+  
+  This program is distributed in the hope that it will be useful, but WITHOUT 
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+  more details.
+  
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59 
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include "e1000.h"
+
+/* Change Log
+ *
+ * 4.4.19       11/27/02
+ *   o Feature: Added user-settable knob for interrupt throttle rate (ITR).
+ *   o Cleanup: removed large static array allocations.
+ *   o Cleanup: C99 struct initializer format.
+ *   o Bug fix: restore VLAN settings when interface is brought up.
+ *   o Bug fix: return cleanly in probe if error in detecting MAC type.
+ *   o Bug fix: Wake up on magic packet by default only if enabled in eeprom.
+ *   o Bug fix: Validate MAC address in set_mac.
+ *   o Bug fix: Throw away zero-length Tx skbs.
+ *   o Bug fix: Make ethtool EEPROM acceses work on older versions of ethtool.
+ * 
+ * 4.4.12       10/15/02
+ *   o Clean up: use members of pci_device rather than direct calls to
+ *     pci_read_config_word.
+ *   o Bug fix: changed default flow control settings.
+ *   o Clean up: ethtool file now has an inclusive list for adapters in the
+ *     Wake-On-LAN capabilities instead of an exclusive list.
+ *   o Bug fix: miscellaneous WoL bug fixes.
+ *   o Added software interrupt for clearing rx ring
+ *   o Bug fix: easier to undo "forcing" of 1000/fd using ethtool.
+ *   o Now setting netdev->mem_end in e1000_probe.
+ *   o Clean up: Moved tx_timeout from interrupt context to process context
+ *     using schedule_task.
+ * 
+ * 4.3.15       8/9/02
+ */
+
+char e1000_driver_name[] = "e1000";
+char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
+char e1000_driver_version[] = "4.4.19-k2";
+char e1000_copyright[] = "Copyright (c) 1999-2002 Intel Corporation.";
+
+/* e1000_pci_tbl - PCI Device ID Table
+ *
+ * Private driver_data field (last one) stores an index into e1000_strings
+ * Wildcard entries (PCI_ANY_ID) should come last
+ * Last entry must be all 0s
+ *
+ * { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
+ *   Class, Class Mask, String Index }
+ */
+static struct pci_device_id e1000_pci_tbl[] __devinitdata = {
+       /* Intel(R) PRO/1000 Network Connection */
+       {0x8086, 0x1000, 0x8086, 0x1000, 0, 0, 0},
+       {0x8086, 0x1001, 0x8086, 0x1003, 0, 0, 0},
+       {0x8086, 0x1004, 0x8086, 0x1004, 0, 0, 0},
+       {0x8086, 0x1008, 0x8086, 0x1107, 0, 0, 0},
+       {0x8086, 0x1009, 0x8086, 0x1109, 0, 0, 0},
+       {0x8086, 0x100C, 0x8086, 0x1112, 0, 0, 0},
+       {0x8086, 0x100E, 0x8086, 0x001E, 0, 0, 0},
+       /* Compaq Gigabit Ethernet Server Adapter */
+       {0x8086, 0x1000, 0x0E11, PCI_ANY_ID, 0, 0, 1},
+       {0x8086, 0x1001, 0x0E11, PCI_ANY_ID, 0, 0, 1},
+       {0x8086, 0x1004, 0x0E11, PCI_ANY_ID, 0, 0, 1},
+       /* IBM Mobile, Desktop & Server Adapters */
+       {0x8086, 0x1000, 0x1014, PCI_ANY_ID, 0, 0, 2},
+       {0x8086, 0x1001, 0x1014, PCI_ANY_ID, 0, 0, 2},
+       {0x8086, 0x1004, 0x1014, PCI_ANY_ID, 0, 0, 2},
+       /* Generic */
+       {0x8086, 0x1000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {0x8086, 0x1001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {0x8086, 0x1004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {0x8086, 0x1008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {0x8086, 0x1009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {0x8086, 0x100C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {0x8086, 0x100D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {0x8086, 0x100E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {0x8086, 0x100F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {0x8086, 0x1011, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {0x8086, 0x1010, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {0x8086, 0x1012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {0x8086, 0x1016, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {0x8086, 0x1017, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       {0x8086, 0x101E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       /* required last entry */
+       {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, e1000_pci_tbl);
+
+static char *e1000_strings[] = {
+       "Intel(R) PRO/1000 Network Connection",
+       "Compaq Gigabit Ethernet Server Adapter",
+       "IBM Mobile, Desktop & Server Adapters"
+};
+
+/* Local Function Prototypes */
+
+int e1000_up(struct e1000_adapter *adapter);
+void e1000_down(struct e1000_adapter *adapter);
+void e1000_reset(struct e1000_adapter *adapter);
+
+static int e1000_init_module(void);
+static void e1000_exit_module(void);
+static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
+static void e1000_remove(struct pci_dev *pdev);
+static int e1000_sw_init(struct e1000_adapter *adapter);
+static int e1000_open(struct net_device *netdev);
+static int e1000_close(struct net_device *netdev);
+static int e1000_setup_tx_resources(struct e1000_adapter *adapter);
+static int e1000_setup_rx_resources(struct e1000_adapter *adapter);
+static void e1000_configure_tx(struct e1000_adapter *adapter);
+static void e1000_configure_rx(struct e1000_adapter *adapter);
+static void e1000_setup_rctl(struct e1000_adapter *adapter);
+static void e1000_clean_tx_ring(struct e1000_adapter *adapter);
+static void e1000_clean_rx_ring(struct e1000_adapter *adapter);
+static void e1000_free_tx_resources(struct e1000_adapter *adapter);
+static void e1000_free_rx_resources(struct e1000_adapter *adapter);
+static void e1000_set_multi(struct net_device *netdev);
+static void e1000_update_phy_info(unsigned long data);
+static void e1000_watchdog(unsigned long data);
+static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
+static struct net_device_stats * e1000_get_stats(struct net_device *netdev);
+static int e1000_change_mtu(struct net_device *netdev, int new_mtu);
+static int e1000_set_mac(struct net_device *netdev, void *p);
+static void e1000_update_stats(struct e1000_adapter *adapter);
+static inline void e1000_irq_disable(struct e1000_adapter *adapter);
+static inline void e1000_irq_enable(struct e1000_adapter *adapter);
+static void e1000_intr(int irq, void *data, struct pt_regs *regs);
+static void e1000_clean_tx_irq(struct e1000_adapter *adapter);
+static void e1000_clean_rx_irq(struct e1000_adapter *adapter);
+static void e1000_alloc_rx_buffers(struct e1000_adapter *adapter);
+static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd);
+static void e1000_enter_82542_rst(struct e1000_adapter *adapter);
+static void e1000_leave_82542_rst(struct e1000_adapter *adapter);
+static inline void e1000_rx_checksum(struct e1000_adapter *adapter,
+                                     struct e1000_rx_desc *rx_desc,
+                                     struct sk_buff *skb);
+static void e1000_tx_timeout(struct net_device *dev);
+static void e1000_tx_timeout_task(struct net_device *dev);
+
+static void e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp);
+static void e1000_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid);
+static void e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid);
+static void e1000_restore_vlan(struct e1000_adapter *adapter);
+
+static int e1000_notify_reboot(struct notifier_block *, unsigned long event, void *ptr);
+static int e1000_suspend(struct pci_dev *pdev, uint32_t state);
+#ifdef CONFIG_PM
+static int e1000_resume(struct pci_dev *pdev);
+#endif
+
+struct notifier_block e1000_notifier_reboot = {
+       .notifier_call  = e1000_notify_reboot,
+       .next           = NULL,
+       .priority       = 0
+};
+
+/* Exported from other modules */
+
+extern void e1000_check_options(struct e1000_adapter *adapter);
+extern int e1000_ethtool_ioctl(struct net_device *netdev, struct ifreq *ifr);
+
+static struct pci_driver e1000_driver = {
+       .name     = e1000_driver_name,
+       .id_table = e1000_pci_tbl,
+       .probe    = e1000_probe,
+       .remove   = __devexit_p(e1000_remove),
+       /* Power Managment Hooks */
+#ifdef CONFIG_PM
+       .suspend  = e1000_suspend,
+       .resume   = e1000_resume
+#endif
+};
+
+MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
+MODULE_DESCRIPTION("Intel(R) PRO/1000 Network Driver");
+MODULE_LICENSE("GPL");
+
+/**
+ * e1000_init_module - Driver Registration Routine
+ *
+ * e1000_init_module is the first routine called when the driver is
+ * loaded. All it does is register with the PCI subsystem.
+ **/
+
+static int __init
+e1000_init_module(void)
+{
+       int ret;
+       printk(KERN_INFO "%s - version %s\n",
+              e1000_driver_string, e1000_driver_version);
+
+       printk(KERN_INFO "%s\n", e1000_copyright);
+
+       ret = pci_module_init(&e1000_driver);
+//     if(ret >= 0)
+//             register_reboot_notifier(&e1000_notifier_reboot);
+       return ret;
+}
+
+module_init(e1000_init_module);
+
+/**
+ * e1000_exit_module - Driver Exit Cleanup Routine
+ *
+ * e1000_exit_module is called just before the driver is removed
+ * from memory.
+ **/
+
+static void __exit
+e1000_exit_module(void)
+{
+//     unregister_reboot_notifier(&e1000_notifier_reboot);
+       pci_unregister_driver(&e1000_driver);
+}
+
+module_exit(e1000_exit_module);
+
+
+int
+e1000_up(struct e1000_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+
+       if(request_irq(netdev->irq, &e1000_intr, SA_SHIRQ | SA_SAMPLE_RANDOM,
+                      netdev->name, netdev))
+               return -1;
+
+       /* hardware has been reset, we need to reload some things */
+
+       e1000_set_multi(netdev);
+       e1000_restore_vlan(adapter);
+
+       e1000_configure_tx(adapter);
+       e1000_setup_rctl(adapter);
+       e1000_configure_rx(adapter);
+       e1000_alloc_rx_buffers(adapter);
+
+       mod_timer(&adapter->watchdog_timer, jiffies);
+       e1000_irq_enable(adapter);
+
+       return 0;
+}
+
+void
+e1000_down(struct e1000_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+
+       e1000_irq_disable(adapter);
+       free_irq(netdev->irq, netdev);
+       del_timer_sync(&adapter->watchdog_timer);
+       del_timer_sync(&adapter->phy_info_timer);
+       adapter->link_speed = 0;
+       adapter->link_duplex = 0;
+       netif_carrier_off(netdev);
+       netif_stop_queue(netdev);
+
+       e1000_reset(adapter);
+       e1000_clean_tx_ring(adapter);
+       e1000_clean_rx_ring(adapter);
+}
+
+void
+e1000_reset(struct e1000_adapter *adapter)
+{
+       /* Repartition Pba for greater than 9k mtu
+        * To take effect CTRL.RST is required.
+        */
+
+       if(adapter->rx_buffer_len > E1000_RXBUFFER_8192)
+               E1000_WRITE_REG(&adapter->hw, PBA, E1000_JUMBO_PBA);
+       else
+               E1000_WRITE_REG(&adapter->hw, PBA, E1000_DEFAULT_PBA);
+
+       adapter->hw.fc = adapter->hw.original_fc;
+       e1000_reset_hw(&adapter->hw);
+printk("RESET_H/W\n");
+       if(adapter->hw.mac_type >= e1000_82544)
+               E1000_WRITE_REG(&adapter->hw, WUC, 0);
+       e1000_init_hw(&adapter->hw);
+printk("INIT H/W\n");
+       e1000_reset_adaptive(&adapter->hw);
+       e1000_phy_get_info(&adapter->hw, &adapter->phy_info);
+}
+
+/**
+ * e1000_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @ent: entry in e1000_pci_tbl
+ *
+ * Returns 0 on success, negative on failure
+ *
+ * e1000_probe initializes an adapter identified by a pci_dev structure.
+ * The OS initialization, configuring of the adapter private structure,
+ * and a hardware reset occur.
+ **/
+
+static int __devinit
+e1000_probe(struct pci_dev *pdev,
+            const struct pci_device_id *ent)
+{
+       struct net_device *netdev;
+       struct e1000_adapter *adapter;
+       static int cards_found = 0;
+       unsigned long mmio_start;
+       int mmio_len;
+       int pci_using_dac;
+       int i;
+       uint16_t eeprom_data;
+
+       if((i = pci_enable_device(pdev)))
+               return i;
+
+       if(!(i = pci_set_dma_mask(pdev, PCI_DMA_64BIT))) {
+               pci_using_dac = 1;
+       } else {
+               if((i = pci_set_dma_mask(pdev, PCI_DMA_32BIT))) {
+                       E1000_ERR("No usable DMA configuration, aborting\n");
+                       return i;
+               }
+               pci_using_dac = 0;
+       }
+
+       if((i = pci_request_regions(pdev, e1000_driver_name)))
+               return i;
+
+       pci_set_master(pdev);
+
+       netdev = alloc_etherdev(sizeof(struct e1000_adapter));
+       if(!netdev)
+               goto err_alloc_etherdev;
+
+       SET_MODULE_OWNER(netdev);
+
+       pci_set_drvdata(pdev, netdev);
+       adapter = netdev->priv;
+       adapter->netdev = netdev;
+       adapter->pdev = pdev;
+       adapter->hw.back = adapter;
+
+       mmio_start = pci_resource_start(pdev, BAR_0);
+       mmio_len = pci_resource_len(pdev, BAR_0);
+
+       adapter->hw.hw_addr = ioremap(mmio_start, mmio_len);
+       if(!adapter->hw.hw_addr)
+               goto err_ioremap;
+
+       for(i = BAR_1; i <= BAR_5; i++) {
+               if(pci_resource_len(pdev, i) == 0)
+                       continue;
+               if(pci_resource_flags(pdev, i) & IORESOURCE_IO) {
+                       adapter->hw.io_base = pci_resource_start(pdev, i);
+                       break;
+               }
+       }
+
+       netdev->open = &e1000_open;
+       netdev->stop = &e1000_close;
+       netdev->hard_start_xmit = &e1000_xmit_frame;
+       netdev->get_stats = &e1000_get_stats;
+       netdev->set_multicast_list = &e1000_set_multi;
+       netdev->set_mac_address = &e1000_set_mac;
+       netdev->change_mtu = &e1000_change_mtu;
+       netdev->do_ioctl = &e1000_ioctl;
+       netdev->tx_timeout = &e1000_tx_timeout;
+       netdev->watchdog_timeo = HZ;
+       netdev->vlan_rx_register = e1000_vlan_rx_register;
+       netdev->vlan_rx_add_vid = e1000_vlan_rx_add_vid;
+       netdev->vlan_rx_kill_vid = e1000_vlan_rx_kill_vid;
+
+       netdev->irq = pdev->irq;
+       netdev->mem_start = mmio_start;
+       netdev->mem_end = mmio_start + mmio_len;
+       netdev->base_addr = adapter->hw.io_base;
+
+       adapter->bd_number = cards_found;
+       adapter->id_string = e1000_strings[ent->driver_data];
+
+       /* setup the private structure */
+
+       if(e1000_sw_init(adapter))
+               goto err_sw_init;
+
+       if(adapter->hw.mac_type >= e1000_82543) {
+               netdev->features = NETIF_F_SG |
+                                  NETIF_F_HW_CSUM |
+                                  NETIF_F_HW_VLAN_TX |
+                                  NETIF_F_HW_VLAN_RX |
+                                  NETIF_F_HW_VLAN_FILTER;
+       } else {
+               netdev->features = NETIF_F_SG;
+       }
+
+       if(pci_using_dac)
+               netdev->features |= NETIF_F_HIGHDMA;
+
+       /* make sure the EEPROM is good */
+
+       if(e1000_validate_eeprom_checksum(&adapter->hw) < 0) {
+               printk(KERN_ERR "The EEPROM Checksum Is Not Valid\n");
+               goto err_eeprom;
+       }
+
+       /* copy the MAC address out of the EEPROM */
+
+       e1000_read_mac_addr(&adapter->hw);
+       memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
+
+       if(!is_valid_ether_addr(netdev->dev_addr))
+               goto err_eeprom;
+
+       e1000_read_part_num(&adapter->hw, &(adapter->part_num));
+
+       e1000_get_bus_info(&adapter->hw);
+
+       if((adapter->hw.mac_type == e1000_82544) &&
+          (adapter->hw.bus_type == e1000_bus_type_pcix))
+
+               adapter->max_data_per_txd = 4096;
+       else
+               adapter->max_data_per_txd = MAX_JUMBO_FRAME_SIZE;
+
+
+       init_timer(&adapter->watchdog_timer);
+       adapter->watchdog_timer.function = &e1000_watchdog;
+       adapter->watchdog_timer.data = (unsigned long) adapter;
+
+       init_timer(&adapter->phy_info_timer);
+       adapter->phy_info_timer.function = &e1000_update_phy_info;
+       adapter->phy_info_timer.data = (unsigned long) adapter;
+
+       INIT_TQUEUE(&adapter->tx_timeout_task,
+               (void (*)(void *))e1000_tx_timeout_task, netdev);
+
+       register_netdev(netdev);
+       memcpy(adapter->ifname, netdev->name, IFNAMSIZ);
+       adapter->ifname[IFNAMSIZ-1] = 0;
+
+       /* we're going to reset, so assume we have no link for now */
+
+       netif_carrier_off(netdev);
+       netif_stop_queue(netdev);
+
+       printk(KERN_INFO "%s: %s\n", netdev->name, adapter->id_string);
+       e1000_check_options(adapter);
+printk("OPTIONS OVER\n");
+       /* Initial Wake on LAN setting
+        * If APM wake is enabled in the EEPROM,
+        * enable the ACPI Magic Packet filter
+        */
+
+       e1000_read_eeprom(&adapter->hw, EEPROM_INIT_CONTROL2_REG, &eeprom_data);
+printk("EPROM OVER\n");
+       if((adapter->hw.mac_type >= e1000_82544) &&
+          (eeprom_data & E1000_EEPROM_APME))
+               adapter->wol |= E1000_WUFC_MAG;
+
+       /* reset the hardware with the new settings */
+
+       e1000_reset(adapter);
+printk("PROBE OVER\n");
+       cards_found++;
+       return 0;
+
+err_sw_init:
+err_eeprom:
+       iounmap(adapter->hw.hw_addr);
+err_ioremap:
+       pci_release_regions(pdev);
+       kfree(netdev);
+err_alloc_etherdev:
+       return -ENOMEM;
+}
+
+/**
+ * e1000_remove - Device Removal Routine
+ * @pdev: PCI device information struct
+ *
+ * e1000_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device.  The could be caused by a
+ * Hot-Plug event, or because the driver is going to be removed from
+ * memory.
+ **/
+
+static void __devexit
+e1000_remove(struct pci_dev *pdev)
+{
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct e1000_adapter *adapter = netdev->priv;
+       uint32_t manc;
+
+       if(adapter->hw.mac_type >= e1000_82540) {
+               manc = E1000_READ_REG(&adapter->hw, MANC);
+               if(manc & E1000_MANC_SMBUS_EN) {
+                       manc |= E1000_MANC_ARP_EN;
+                       E1000_WRITE_REG(&adapter->hw, MANC, manc);
+               }
+       }
+
+       unregister_netdev(netdev);
+
+       e1000_phy_hw_reset(&adapter->hw);
+
+       iounmap(adapter->hw.hw_addr);
+       pci_release_regions(pdev);
+
+       kfree(netdev);
+}
+
+/**
+ * e1000_sw_init - Initialize general software structures (struct e1000_adapter)
+ * @adapter: board private structure to initialize
+ *
+ * e1000_sw_init initializes the Adapter private data structure.
+ * Fields are initialized based on PCI device information and
+ * OS network device settings (MTU size).
+ **/
+
+static int __devinit
+e1000_sw_init(struct e1000_adapter *adapter)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       struct net_device *netdev = adapter->netdev;
+       struct pci_dev *pdev = adapter->pdev;
+
+       /* PCI config space info */
+
+       hw->vendor_id = pdev->vendor;
+       hw->device_id = pdev->device;
+       hw->subsystem_vendor_id = pdev->subsystem_vendor;
+       hw->subsystem_id = pdev->subsystem_device;
+
+       pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id);
+
+       pci_read_config_word(pdev, PCI_COMMAND, &hw->pci_cmd_word);
+
+       adapter->rx_buffer_len = E1000_RXBUFFER_2048;
+       hw->max_frame_size = netdev->mtu +
+                                ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
+       hw->min_frame_size = MINIMUM_ETHERNET_FRAME_SIZE;
+
+       /* identify the MAC */
+
+       if (e1000_set_mac_type(hw)) {
+               E1000_ERR("Unknown MAC Type\n");
+               return -1;
+       }
+
+       /* flow control settings */
+
+       hw->fc_high_water = E1000_FC_HIGH_THRESH;
+       hw->fc_low_water = E1000_FC_LOW_THRESH;
+       hw->fc_pause_time = E1000_FC_PAUSE_TIME;
+       hw->fc_send_xon = 1;
+
+       /* Media type - copper or fiber */
+
+       if(hw->mac_type >= e1000_82543) {
+               uint32_t status = E1000_READ_REG(hw, STATUS);
+
+               if(status & E1000_STATUS_TBIMODE)
+                       hw->media_type = e1000_media_type_fiber;
+               else
+                       hw->media_type = e1000_media_type_copper;
+       } else {
+               hw->media_type = e1000_media_type_fiber;
+       }
+
+       if(hw->mac_type < e1000_82543)
+               hw->report_tx_early = 0;
+       else
+               hw->report_tx_early = 1;
+
+       hw->wait_autoneg_complete = FALSE;
+       hw->tbi_compatibility_en = TRUE;
+       hw->adaptive_ifs = TRUE;
+
+       /* Copper options */
+
+       if(hw->media_type == e1000_media_type_copper) {
+               hw->mdix = AUTO_ALL_MODES;
+               hw->disable_polarity_correction = FALSE;
+       }
+
+       atomic_set(&adapter->irq_sem, 1);
+       spin_lock_init(&adapter->stats_lock);
+
+       return 0;
+}
+
+/**
+ * e1000_open - Called when a network interface is made active
+ * @netdev: network interface device structure
+ *
+ * Returns 0 on success, negative value on failure
+ *
+ * The open entry point is called when a network interface is made
+ * active by the system (IFF_UP).  At this point all resources needed
+ * for transmit and receive operations are allocated, the interrupt
+ * handler is registered with the OS, the watchdog timer is started,
+ * and the stack is notified that the interface is ready.
+ **/
+
+static int
+e1000_open(struct net_device *netdev)
+{
+       struct e1000_adapter *adapter = netdev->priv;
+
+       /* allocate transmit descriptors */
+
+       if(e1000_setup_tx_resources(adapter))
+               goto err_setup_tx;
+
+       /* allocate receive descriptors */
+
+       if(e1000_setup_rx_resources(adapter))
+               goto err_setup_rx;
+
+       if(e1000_up(adapter))
+               goto err_up;
+
+       return 0;
+
+err_up:
+       e1000_free_rx_resources(adapter);
+err_setup_rx:
+       e1000_free_tx_resources(adapter);
+err_setup_tx:
+       e1000_reset(adapter);
+
+       return -EBUSY;
+}
+
+/**
+ * e1000_close - Disables a network interface
+ * @netdev: network interface device structure
+ *
+ * Returns 0, this is not allowed to fail
+ *
+ * The close entry point is called when an interface is de-activated
+ * by the OS.  The hardware is still under the drivers control, but
+ * needs to be disabled.  A global MAC reset is issued to stop the
+ * hardware, and all transmit and receive resources are freed.
+ **/
+
+static int
+e1000_close(struct net_device *netdev)
+{
+       struct e1000_adapter *adapter = netdev->priv;
+
+       e1000_down(adapter);
+
+       e1000_free_tx_resources(adapter);
+       e1000_free_rx_resources(adapter);
+
+       return 0;
+}
+
+/**
+ * e1000_setup_tx_resources - allocate Tx resources (Descriptors)
+ * @adapter: board private structure
+ *
+ * Return 0 on success, negative on failure
+ **/
+
+static int
+e1000_setup_tx_resources(struct e1000_adapter *adapter)
+{
+       struct e1000_desc_ring *txdr = &adapter->tx_ring;
+       struct pci_dev *pdev = adapter->pdev;
+       int size;
+
+       size = sizeof(struct e1000_buffer) * txdr->count;
+       txdr->buffer_info = kmalloc(size, GFP_KERNEL);
+       if(!txdr->buffer_info) {
+               return -ENOMEM;
+       }
+       memset(txdr->buffer_info, 0, size);
+
+       /* round up to nearest 4K */
+
+       txdr->size = txdr->count * sizeof(struct e1000_tx_desc);
+       E1000_ROUNDUP(txdr->size, 4096);
+
+       txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma);
+       if(!txdr->desc) {
+               kfree(txdr->buffer_info);
+               return -ENOMEM;
+       }
+       memset(txdr->desc, 0, txdr->size);
+
+       txdr->next_to_use = 0;
+       txdr->next_to_clean = 0;
+
+       return 0;
+}
+
+/**
+ * e1000_configure_tx - Configure 8254x Transmit Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Tx unit of the MAC after a reset.
+ **/
+
+static void
+e1000_configure_tx(struct e1000_adapter *adapter)
+{
+       uint64_t tdba = adapter->tx_ring.dma;
+       uint32_t tdlen = adapter->tx_ring.count * sizeof(struct e1000_tx_desc);
+       uint32_t tctl, tipg;
+
+       E1000_WRITE_REG(&adapter->hw, TDBAL, (tdba & 0x00000000ffffffffULL));
+       E1000_WRITE_REG(&adapter->hw, TDBAH, (tdba >> 32));
+
+       E1000_WRITE_REG(&adapter->hw, TDLEN, tdlen);
+
+       /* Setup the HW Tx Head and Tail descriptor pointers */
+
+       E1000_WRITE_REG(&adapter->hw, TDH, 0);
+       E1000_WRITE_REG(&adapter->hw, TDT, 0);
+
+       /* Set the default values for the Tx Inter Packet Gap timer */
+
+       switch (adapter->hw.mac_type) {
+       case e1000_82542_rev2_0:
+       case e1000_82542_rev2_1:
+               tipg = DEFAULT_82542_TIPG_IPGT;
+               tipg |= DEFAULT_82542_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT;
+               tipg |= DEFAULT_82542_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
+               break;
+       default:
+               if(adapter->hw.media_type == e1000_media_type_fiber)
+                       tipg = DEFAULT_82543_TIPG_IPGT_FIBER;
+               else
+                       tipg = DEFAULT_82543_TIPG_IPGT_COPPER;
+               tipg |= DEFAULT_82543_TIPG_IPGR1 << E1000_TIPG_IPGR1_SHIFT;
+               tipg |= DEFAULT_82543_TIPG_IPGR2 << E1000_TIPG_IPGR2_SHIFT;
+       }
+       E1000_WRITE_REG(&adapter->hw, TIPG, tipg);
+
+       /* Set the Tx Interrupt Delay register */
+
+       E1000_WRITE_REG(&adapter->hw, TIDV, adapter->tx_int_delay);
+       if(adapter->hw.mac_type >= e1000_82540)
+               E1000_WRITE_REG(&adapter->hw, TADV, adapter->tx_abs_int_delay);
+
+       /* Program the Transmit Control Register */
+
+       tctl = E1000_READ_REG(&adapter->hw, TCTL);
+
+       tctl &= ~E1000_TCTL_CT;
+       tctl |= E1000_TCTL_EN | E1000_TCTL_PSP |
+              (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
+
+       E1000_WRITE_REG(&adapter->hw, TCTL, tctl);
+
+       e1000_config_collision_dist(&adapter->hw);
+
+       /* Setup Transmit Descriptor Settings for this adapter */
+       adapter->txd_cmd = E1000_TXD_CMD_IFCS | E1000_TXD_CMD_IDE;
+
+       if(adapter->hw.report_tx_early == 1)
+               adapter->txd_cmd |= E1000_TXD_CMD_RS;
+       else
+               adapter->txd_cmd |= E1000_TXD_CMD_RPS;
+}
+
+/**
+ * e1000_setup_rx_resources - allocate Rx resources (Descriptors)
+ * @adapter: board private structure
+ *
+ * Returns 0 on success, negative on failure
+ **/
+
+static int
+e1000_setup_rx_resources(struct e1000_adapter *adapter)
+{
+       struct e1000_desc_ring *rxdr = &adapter->rx_ring;
+       struct pci_dev *pdev = adapter->pdev;
+       int size;
+
+       size = sizeof(struct e1000_buffer) * rxdr->count;
+       rxdr->buffer_info = kmalloc(size, GFP_KERNEL);
+       if(!rxdr->buffer_info) {
+               return -ENOMEM;
+       }
+       memset(rxdr->buffer_info, 0, size);
+
+       /* Round up to nearest 4K */
+
+       rxdr->size = rxdr->count * sizeof(struct e1000_rx_desc);
+       E1000_ROUNDUP(rxdr->size, 4096);
+
+       rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma);
+
+       if(!rxdr->desc) {
+               kfree(rxdr->buffer_info);
+               return -ENOMEM;
+       }
+       memset(rxdr->desc, 0, rxdr->size);
+
+       rxdr->next_to_clean = 0;
+       rxdr->next_to_use = 0;
+
+       return 0;
+}
+
+/**
+ * e1000_setup_rctl - configure the receive control register
+ * @adapter: Board private structure
+ **/
+
+static void
+e1000_setup_rctl(struct e1000_adapter *adapter)
+{
+       uint32_t rctl;
+
+       rctl = E1000_READ_REG(&adapter->hw, RCTL);
+
+       rctl &= ~(3 << E1000_RCTL_MO_SHIFT);
+
+       rctl |= E1000_RCTL_EN | E1000_RCTL_BAM |
+               E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF |
+               (adapter->hw.mc_filter_type << E1000_RCTL_MO_SHIFT);
+
+       if(adapter->hw.tbi_compatibility_on == 1)
+               rctl |= E1000_RCTL_SBP;
+       else
+               rctl &= ~E1000_RCTL_SBP;
+
+       rctl &= ~(E1000_RCTL_SZ_4096);
+       switch (adapter->rx_buffer_len) {
+       case E1000_RXBUFFER_2048:
+       default:
+               rctl |= E1000_RCTL_SZ_2048;
+               rctl &= ~(E1000_RCTL_BSEX | E1000_RCTL_LPE);
+               break;
+       case E1000_RXBUFFER_4096:
+               rctl |= E1000_RCTL_SZ_4096 | E1000_RCTL_BSEX | E1000_RCTL_LPE;
+               break;
+       case E1000_RXBUFFER_8192:
+               rctl |= E1000_RCTL_SZ_8192 | E1000_RCTL_BSEX | E1000_RCTL_LPE;
+               break;
+       case E1000_RXBUFFER_16384:
+               rctl |= E1000_RCTL_SZ_16384 | E1000_RCTL_BSEX | E1000_RCTL_LPE;
+               break;
+       }
+
+       E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
+}
+
+/**
+ * e1000_configure_rx - Configure 8254x Receive Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Rx unit of the MAC after a reset.
+ **/
+
+static void
+e1000_configure_rx(struct e1000_adapter *adapter)
+{
+       uint64_t rdba = adapter->rx_ring.dma;
+       uint32_t rdlen = adapter->rx_ring.count * sizeof(struct e1000_rx_desc);
+       uint32_t rctl;
+       uint32_t rxcsum;
+
+       /* make sure receives are disabled while setting up the descriptors */
+
+       rctl = E1000_READ_REG(&adapter->hw, RCTL);
+       E1000_WRITE_REG(&adapter->hw, RCTL, rctl & ~E1000_RCTL_EN);
+
+       /* set the Receive Delay Timer Register */
+
+       E1000_WRITE_REG(&adapter->hw, RDTR, adapter->rx_int_delay);
+
+       if(adapter->hw.mac_type >= e1000_82540) {
+               E1000_WRITE_REG(&adapter->hw, RADV, adapter->rx_abs_int_delay);
+
+               /* Set the interrupt throttling rate.  Value is calculated
+                * as DEFAULT_ITR = 1/(MAX_INTS_PER_SEC * 256ns) */
+#define MAX_INTS_PER_SEC        8000
+#define DEFAULT_ITR             1000000000/(MAX_INTS_PER_SEC * 256)
+               E1000_WRITE_REG(&adapter->hw, ITR, DEFAULT_ITR);
+       }
+
+       /* Setup the Base and Length of the Rx Descriptor Ring */
+
+       E1000_WRITE_REG(&adapter->hw, RDBAL, (rdba & 0x00000000ffffffffULL));
+       E1000_WRITE_REG(&adapter->hw, RDBAH, (rdba >> 32));
+
+       E1000_WRITE_REG(&adapter->hw, RDLEN, rdlen);
+
+       /* Setup the HW Rx Head and Tail Descriptor Pointers */
+       E1000_WRITE_REG(&adapter->hw, RDH, 0);
+       E1000_WRITE_REG(&adapter->hw, RDT, 0);
+
+       /* Enable 82543 Receive Checksum Offload for TCP and UDP */
+       if((adapter->hw.mac_type >= e1000_82543) &&
+          (adapter->rx_csum == TRUE)) {
+               rxcsum = E1000_READ_REG(&adapter->hw, RXCSUM);
+               rxcsum |= E1000_RXCSUM_TUOFL;
+               E1000_WRITE_REG(&adapter->hw, RXCSUM, rxcsum);
+       }
+
+       /* Enable Receives */
+
+       E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
+}
+
+/**
+ * e1000_free_tx_resources - Free Tx Resources
+ * @adapter: board private structure
+ *
+ * Free all transmit software resources
+ **/
+
+static void
+e1000_free_tx_resources(struct e1000_adapter *adapter)
+{
+       struct pci_dev *pdev = adapter->pdev;
+
+       e1000_clean_tx_ring(adapter);
+
+       kfree(adapter->tx_ring.buffer_info);
+       adapter->tx_ring.buffer_info = NULL;
+
+       pci_free_consistent(pdev, adapter->tx_ring.size,
+                           adapter->tx_ring.desc, adapter->tx_ring.dma);
+
+       adapter->tx_ring.desc = NULL;
+}
+
+/**
+ * e1000_clean_tx_ring - Free Tx Buffers
+ * @adapter: board private structure
+ **/
+
+static void
+e1000_clean_tx_ring(struct e1000_adapter *adapter)
+{
+       struct pci_dev *pdev = adapter->pdev;
+       unsigned long size;
+       int i;
+
+       /* Free all the Tx ring sk_buffs */
+
+       for(i = 0; i < adapter->tx_ring.count; i++) {
+               if(adapter->tx_ring.buffer_info[i].skb) {
+
+                       pci_unmap_page(pdev,
+                                      adapter->tx_ring.buffer_info[i].dma,
+                                      adapter->tx_ring.buffer_info[i].length,
+                                      PCI_DMA_TODEVICE);
+
+                       dev_kfree_skb(adapter->tx_ring.buffer_info[i].skb);
+
+                       adapter->tx_ring.buffer_info[i].skb = NULL;
+               }
+       }
+
+       size = sizeof(struct e1000_buffer) * adapter->tx_ring.count;
+       memset(adapter->tx_ring.buffer_info, 0, size);
+
+       /* Zero out the descriptor ring */
+
+       memset(adapter->tx_ring.desc, 0, adapter->tx_ring.size);
+
+       adapter->tx_ring.next_to_use = 0;
+       adapter->tx_ring.next_to_clean = 0;
+
+       E1000_WRITE_REG(&adapter->hw, TDH, 0);
+       E1000_WRITE_REG(&adapter->hw, TDT, 0);
+}
+
+/**
+ * e1000_free_rx_resources - Free Rx Resources
+ * @adapter: board private structure
+ *
+ * Free all receive software resources
+ **/
+
+static void
+e1000_free_rx_resources(struct e1000_adapter *adapter)
+{
+       struct pci_dev *pdev = adapter->pdev;
+
+       e1000_clean_rx_ring(adapter);
+
+       kfree(adapter->rx_ring.buffer_info);
+       adapter->rx_ring.buffer_info = NULL;
+
+       pci_free_consistent(pdev, adapter->rx_ring.size,
+                           adapter->rx_ring.desc, adapter->rx_ring.dma);
+
+       adapter->rx_ring.desc = NULL;
+}
+
+/**
+ * e1000_clean_rx_ring - Free Rx Buffers
+ * @adapter: board private structure
+ **/
+
+static void
+e1000_clean_rx_ring(struct e1000_adapter *adapter)
+{
+       struct pci_dev *pdev = adapter->pdev;
+       unsigned long size;
+       int i;
+
+       /* Free all the Rx ring sk_buffs */
+
+       for(i = 0; i < adapter->rx_ring.count; i++) {
+               if(adapter->rx_ring.buffer_info[i].skb) {
+
+                       pci_unmap_single(pdev,
+                                        adapter->rx_ring.buffer_info[i].dma,
+                                        adapter->rx_ring.buffer_info[i].length,
+                                        PCI_DMA_FROMDEVICE);
+
+                       dev_kfree_skb(adapter->rx_ring.buffer_info[i].skb);
+
+                       adapter->rx_ring.buffer_info[i].skb = NULL;
+               }
+       }
+
+       size = sizeof(struct e1000_buffer) * adapter->rx_ring.count;
+       memset(adapter->rx_ring.buffer_info, 0, size);
+
+       /* Zero out the descriptor ring */
+
+       memset(adapter->rx_ring.desc, 0, adapter->rx_ring.size);
+
+       adapter->rx_ring.next_to_clean = 0;
+       adapter->rx_ring.next_to_use = 0;
+
+       E1000_WRITE_REG(&adapter->hw, RDH, 0);
+       E1000_WRITE_REG(&adapter->hw, RDT, 0);
+}
+
+/* The 82542 2.0 (revision 2) needs to have the receive unit in reset
+ * and memory write and invalidate disabled for certain operations
+ */
+static void
+e1000_enter_82542_rst(struct e1000_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+       uint32_t rctl;
+
+       e1000_pci_clear_mwi(&adapter->hw);
+
+       rctl = E1000_READ_REG(&adapter->hw, RCTL);
+       rctl |= E1000_RCTL_RST;
+       E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
+       E1000_WRITE_FLUSH(&adapter->hw);
+       mdelay(5);
+
+       if(netif_running(netdev))
+               e1000_clean_rx_ring(adapter);
+}
+
+static void
+e1000_leave_82542_rst(struct e1000_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+       uint32_t rctl;
+
+       rctl = E1000_READ_REG(&adapter->hw, RCTL);
+       rctl &= ~E1000_RCTL_RST;
+       E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
+       E1000_WRITE_FLUSH(&adapter->hw);
+       mdelay(5);
+
+       if(adapter->hw.pci_cmd_word & PCI_COMMAND_INVALIDATE)
+               e1000_pci_set_mwi(&adapter->hw);
+
+       if(netif_running(netdev)) {
+               e1000_configure_rx(adapter);
+               e1000_alloc_rx_buffers(adapter);
+       }
+}
+
+/**
+ * e1000_set_mac - Change the Ethernet Address of the NIC
+ * @netdev: network interface device structure
+ * @p: pointer to an address structure
+ *
+ * Returns 0 on success, negative on failure
+ **/
+
+static int
+e1000_set_mac(struct net_device *netdev, void *p)
+{
+       struct e1000_adapter *adapter = netdev->priv;
+       struct sockaddr *addr = p;
+
+       if(!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+
+       /* 82542 2.0 needs to be in reset to write receive address registers */
+
+       if(adapter->hw.mac_type == e1000_82542_rev2_0)
+               e1000_enter_82542_rst(adapter);
+
+       memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+       memcpy(adapter->hw.mac_addr, addr->sa_data, netdev->addr_len);
+
+       e1000_rar_set(&adapter->hw, adapter->hw.mac_addr, 0);
+
+       if(adapter->hw.mac_type == e1000_82542_rev2_0)
+               e1000_leave_82542_rst(adapter);
+
+       return 0;
+}
+
+/**
+ * e1000_set_multi - Multicast and Promiscuous mode set
+ * @netdev: network interface device structure
+ *
+ * The set_multi entry point is called whenever the multicast address
+ * list or the network interface flags are updated.  This routine is
+ * resposible for configuring the hardware for proper multicast,
+ * promiscuous mode, and all-multi behavior.
+ **/
+
+static void
+e1000_set_multi(struct net_device *netdev)
+{
+       struct e1000_adapter *adapter = netdev->priv;
+       struct e1000_hw *hw = &adapter->hw;
+       struct dev_mc_list *mc_ptr;
+       uint32_t rctl;
+       uint32_t hash_value;
+       int i;
+
+       /* Check for Promiscuous and All Multicast modes */
+
+       rctl = E1000_READ_REG(hw, RCTL);
+
+       if(netdev->flags & IFF_PROMISC) {
+               rctl |= (E1000_RCTL_UPE | E1000_RCTL_MPE);
+       } else if(netdev->flags & IFF_ALLMULTI) {
+               rctl |= E1000_RCTL_MPE;
+               rctl &= ~E1000_RCTL_UPE;
+       } else {
+               rctl &= ~(E1000_RCTL_UPE | E1000_RCTL_MPE);
+       }
+
+       E1000_WRITE_REG(hw, RCTL, rctl);
+
+       /* 82542 2.0 needs to be in reset to write receive address registers */
+
+       if(hw->mac_type == e1000_82542_rev2_0)
+               e1000_enter_82542_rst(adapter);
+
+       /* load the first 15 multicast address into the exact filters 1-15
+        * RAR 0 is used for the station MAC adddress
+        * if there are not 15 addresses, go ahead and clear the filters
+        */
+       mc_ptr = netdev->mc_list;
+
+       for(i = 1; i < E1000_RAR_ENTRIES; i++) {
+               if(mc_ptr) {
+                       e1000_rar_set(hw, mc_ptr->dmi_addr, i);
+                       mc_ptr = mc_ptr->next;
+               } else {
+                       E1000_WRITE_REG_ARRAY(hw, RA, i << 1, 0);
+                       E1000_WRITE_REG_ARRAY(hw, RA, (i << 1) + 1, 0);
+               }
+       }
+
+       /* clear the old settings from the multicast hash table */
+
+       for(i = 0; i < E1000_NUM_MTA_REGISTERS; i++)
+               E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
+
+       /* load any remaining addresses into the hash table */
+
+       for(; mc_ptr; mc_ptr = mc_ptr->next) {
+               hash_value = e1000_hash_mc_addr(hw, mc_ptr->dmi_addr);
+               e1000_mta_set(hw, hash_value);
+       }
+
+       if(hw->mac_type == e1000_82542_rev2_0)
+               e1000_leave_82542_rst(adapter);
+}
+
+
+/* need to wait a few seconds after link up to get diagnostic information from the phy */
+
+static void
+e1000_update_phy_info(unsigned long data)
+{
+       struct e1000_adapter *adapter = (struct e1000_adapter *) data;
+       e1000_phy_get_info(&adapter->hw, &adapter->phy_info);
+}
+
+/**
+ * e1000_watchdog - Timer Call-back
+ * @data: pointer to netdev cast into an unsigned long
+ **/
+
+static void
+e1000_watchdog(unsigned long data)
+{
+       struct e1000_adapter *adapter = (struct e1000_adapter *) data;
+       struct net_device *netdev = adapter->netdev;
+       struct e1000_desc_ring *txdr = &adapter->tx_ring;
+       int i;
+
+       e1000_check_for_link(&adapter->hw);
+
+       if(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_LU) {
+               if(!netif_carrier_ok(netdev)) {
+                       e1000_get_speed_and_duplex(&adapter->hw,
+                                                  &adapter->link_speed,
+                                                  &adapter->link_duplex);
+
+                       printk(KERN_INFO
+                              "e1000: %s NIC Link is Up %d Mbps %s\n",
+                              netdev->name, adapter->link_speed,
+                              adapter->link_duplex == FULL_DUPLEX ?
+                              "Full Duplex" : "Half Duplex");
+
+                       netif_carrier_on(netdev);
+                       netif_wake_queue(netdev);
+                       mod_timer(&adapter->phy_info_timer, jiffies + 2 * HZ);
+               }
+       } else {
+               if(netif_carrier_ok(netdev)) {
+                       adapter->link_speed = 0;
+                       adapter->link_duplex = 0;
+                       printk(KERN_INFO
+                              "e1000: %s NIC Link is Down\n",
+                              netdev->name);
+                       netif_carrier_off(netdev);
+                       netif_stop_queue(netdev);
+                       mod_timer(&adapter->phy_info_timer, jiffies + 2 * HZ);
+               }
+       }
+
+       e1000_update_stats(adapter);
+       e1000_update_adaptive(&adapter->hw);
+
+
+       /* Cause software interrupt to ensure rx ring is cleaned */
+       E1000_WRITE_REG(&adapter->hw, ICS, E1000_ICS_RXDMT0);
+
+       /* Early detection of hung controller */
+       i = txdr->next_to_clean;
+       if(txdr->buffer_info[i].dma &&
+          time_after(jiffies, txdr->buffer_info[i].time_stamp + HZ) &&
+          !(E1000_READ_REG(&adapter->hw, STATUS) & E1000_STATUS_TXOFF))
+               netif_stop_queue(netdev);
+
+       /* Reset the timer */
+       mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);
+}
+
+#define E1000_TX_FLAGS_CSUM            0x00000001
+#define E1000_TX_FLAGS_VLAN            0x00000002
+#define E1000_TX_FLAGS_VLAN_MASK       0xffff0000
+#define E1000_TX_FLAGS_VLAN_SHIFT      16
+
+static inline boolean_t
+e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb)
+{
+       struct e1000_context_desc *context_desc;
+       int i;
+       uint8_t css, cso;
+
+       if(skb->ip_summed == CHECKSUM_HW) {
+               css = skb->h.raw - skb->data;
+               cso = (skb->h.raw + skb->csum) - skb->data;
+
+               i = adapter->tx_ring.next_to_use;
+               context_desc = E1000_CONTEXT_DESC(adapter->tx_ring, i);
+
+               context_desc->upper_setup.tcp_fields.tucss = css;
+               context_desc->upper_setup.tcp_fields.tucso = cso;
+               context_desc->upper_setup.tcp_fields.tucse = 0;
+               context_desc->tcp_seg_setup.data = 0;
+               context_desc->cmd_and_length =
+                       cpu_to_le32(adapter->txd_cmd | E1000_TXD_CMD_DEXT);
+
+               i = (i + 1) % adapter->tx_ring.count;
+               adapter->tx_ring.next_to_use = i;
+
+               return TRUE;
+       }
+
+       return FALSE;
+}
+
+static inline int
+e1000_tx_map(struct e1000_adapter *adapter, struct sk_buff *skb)
+{
+       struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
+       int len, offset, size, count, i;
+
+       int f;
+       len = skb->len - skb->data_len;
+       i = (tx_ring->next_to_use + tx_ring->count - 1) % tx_ring->count;
+       count = 0;
+
+       offset = 0;
+
+       while(len) {
+               i = (i + 1) % tx_ring->count;
+               size = min(len, adapter->max_data_per_txd);
+               tx_ring->buffer_info[i].length = size;
+               tx_ring->buffer_info[i].dma =
+                       pci_map_single(adapter->pdev,
+                               skb->data + offset,
+                               size,
+                               PCI_DMA_TODEVICE);
+               tx_ring->buffer_info[i].time_stamp = jiffies;
+
+               len -= size;
+               offset += size;
+               count++;
+       }
+
+       for(f = 0; f < skb_shinfo(skb)->nr_frags; f++) {
+               struct skb_frag_struct *frag;
+
+               frag = &skb_shinfo(skb)->frags[f];
+               len = frag->size;
+               offset = 0;
+
+               while(len) {
+                       i = (i + 1) % tx_ring->count;
+                       size = min(len, adapter->max_data_per_txd);
+                       tx_ring->buffer_info[i].length = size;
+                       tx_ring->buffer_info[i].dma =
+                               pci_map_page(adapter->pdev,
+                                       frag->page,
+                                       frag->page_offset + offset,
+                                       size,
+                                       PCI_DMA_TODEVICE);
+
+                       len -= size;
+                       offset += size;
+                       count++;
+               }
+       }
+       tx_ring->buffer_info[i].skb = skb;
+
+       return count;
+}
+
+static inline void
+e1000_tx_queue(struct e1000_adapter *adapter, int count, int tx_flags)
+{
+       struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
+       struct e1000_tx_desc *tx_desc = NULL;
+       uint32_t txd_upper, txd_lower;
+       int i;
+
+       txd_upper = 0;
+       txd_lower = adapter->txd_cmd;
+
+       if(tx_flags & E1000_TX_FLAGS_CSUM) {
+               txd_lower |= E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D;
+               txd_upper |= E1000_TXD_POPTS_TXSM << 8;
+       }
+
+       if(tx_flags & E1000_TX_FLAGS_VLAN) {
+               txd_lower |= E1000_TXD_CMD_VLE;
+               txd_upper |= (tx_flags & E1000_TX_FLAGS_VLAN_MASK);
+       }
+
+       i = tx_ring->next_to_use;
+
+       while(count--) {
+               tx_desc = E1000_TX_DESC(*tx_ring, i);
+               tx_desc->buffer_addr = cpu_to_le64(tx_ring->buffer_info[i].dma);
+               tx_desc->lower.data =
+                       cpu_to_le32(txd_lower | tx_ring->buffer_info[i].length);
+               tx_desc->upper.data = cpu_to_le32(txd_upper);
+               i = (i + 1) % tx_ring->count;
+       }
+
+       tx_desc->lower.data |= cpu_to_le32(E1000_TXD_CMD_EOP);
+
+       /* Force memory writes to complete before letting h/w
+        * know there are new descriptors to fetch.  (Only
+        * applicable for weak-ordered memory model archs,
+        * such as IA-64). */
+       wmb();
+
+       tx_ring->next_to_use = i;
+       E1000_WRITE_REG(&adapter->hw, TDT, i);
+}
+
+#define TXD_USE_COUNT(S, X) (((S) / (X)) + (((S) % (X)) ? 1 : 0))
+
+static int
+e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+       struct e1000_adapter *adapter = netdev->priv;
+       int tx_flags = 0, count;
+       int f;
+
+       count = TXD_USE_COUNT(skb->len - skb->data_len,
+                             adapter->max_data_per_txd);
+
+       if(count == 0) {
+               dev_kfree_skb_any(skb);
+               return 0;
+       }
+
+       for(f = 0; f < skb_shinfo(skb)->nr_frags; f++)
+               count += TXD_USE_COUNT(skb_shinfo(skb)->frags[f].size,
+                                      adapter->max_data_per_txd);
+
+       if(skb->ip_summed == CHECKSUM_HW)
+               count++;
+
+       if(E1000_DESC_UNUSED(&adapter->tx_ring) < count) {
+               netif_stop_queue(netdev);
+               return 1;
+       }
+
+       if(e1000_tx_csum(adapter, skb))
+               tx_flags |= E1000_TX_FLAGS_CSUM;
+
+       if(adapter->vlgrp && vlan_tx_tag_present(skb)) {
+               tx_flags |= E1000_TX_FLAGS_VLAN;
+               tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT);
+       }
+
+       count = e1000_tx_map(adapter, skb);
+
+       e1000_tx_queue(adapter, count, tx_flags);
+
+       netdev->trans_start = jiffies;
+
+       return 0;
+}
+
+/**
+ * e1000_tx_timeout - Respond to a Tx Hang
+ * @netdev: network interface device structure
+ **/
+
+static void
+e1000_tx_timeout(struct net_device *netdev)
+{
+       struct e1000_adapter *adapter = netdev->priv;
+
+       /* Do the reset outside of interrupt context */
+       //schedule_task(&adapter->tx_timeout_task); XXXX Not in Xen!!!
+       e1000_tx_timeout_task(netdev);  // XXX HACK
+}
+
+static void
+e1000_tx_timeout_task(struct net_device *netdev)
+{
+       struct e1000_adapter *adapter = netdev->priv;
+
+       netif_device_detach(netdev);
+       e1000_down(adapter);
+       e1000_up(adapter);
+       netif_device_attach(netdev);
+}
+
+/**
+ * e1000_get_stats - Get System Network Statistics
+ * @netdev: network interface device structure
+ *
+ * Returns the address of the device statistics structure.
+ * The statistics are actually updated from the timer callback.
+ **/
+
+static struct net_device_stats *
+e1000_get_stats(struct net_device *netdev)
+{
+       struct e1000_adapter *adapter = netdev->priv;
+
+       return &adapter->net_stats;
+}
+
+/**
+ * e1000_change_mtu - Change the Maximum Transfer Unit
+ * @netdev: network interface device structure
+ * @new_mtu: new value for maximum frame size
+ *
+ * Returns 0 on success, negative on failure
+ **/
+
+static int
+e1000_change_mtu(struct net_device *netdev, int new_mtu)
+{
+       struct e1000_adapter *adapter = netdev->priv;
+       int old_mtu = adapter->rx_buffer_len;
+       int max_frame = new_mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
+
+       if((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) ||
+          (max_frame > MAX_JUMBO_FRAME_SIZE)) {
+               E1000_ERR("Invalid MTU setting\n");
+               return -EINVAL;
+       }
+
+       if(max_frame <= MAXIMUM_ETHERNET_FRAME_SIZE) {
+               adapter->rx_buffer_len = E1000_RXBUFFER_2048;
+
+       } else if(adapter->hw.mac_type < e1000_82543) {
+               E1000_ERR("Jumbo Frames not supported on 82542\n");
+               return -EINVAL;
+
+       } else if(max_frame <= E1000_RXBUFFER_4096) {
+               adapter->rx_buffer_len = E1000_RXBUFFER_4096;
+
+       } else if(max_frame <= E1000_RXBUFFER_8192) {
+               adapter->rx_buffer_len = E1000_RXBUFFER_8192;
+
+       } else {
+               adapter->rx_buffer_len = E1000_RXBUFFER_16384;
+       }
+
+       if(old_mtu != adapter->rx_buffer_len && netif_running(netdev)) {
+
+               e1000_down(adapter);
+               e1000_up(adapter);
+       }
+
+       netdev->mtu = new_mtu;
+       adapter->hw.max_frame_size = max_frame;
+
+       return 0;
+}
+
+/**
+ * e1000_update_stats - Update the board statistics counters
+ * @adapter: board private structure
+ **/
+
+static void
+e1000_update_stats(struct e1000_adapter *adapter)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       unsigned long flags;
+       uint16_t phy_tmp;
+
+#define PHY_IDLE_ERROR_COUNT_MASK 0x00FF
+
+       spin_lock_irqsave(&adapter->stats_lock, flags);
+
+       /* these counters are modified from e1000_adjust_tbi_stats,
+        * called from the interrupt context, so they must only
+        * be written while holding adapter->stats_lock
+        */
+
+       adapter->stats.crcerrs += E1000_READ_REG(hw, CRCERRS);
+       adapter->stats.gprc += E1000_READ_REG(hw, GPRC);
+       adapter->stats.gorcl += E1000_READ_REG(hw, GORCL);
+       adapter->stats.gorch += E1000_READ_REG(hw, GORCH);
+       adapter->stats.bprc += E1000_READ_REG(hw, BPRC);
+       adapter->stats.mprc += E1000_READ_REG(hw, MPRC);
+       adapter->stats.roc += E1000_READ_REG(hw, ROC);
+       adapter->stats.prc64 += E1000_READ_REG(hw, PRC64);
+       adapter->stats.prc127 += E1000_READ_REG(hw, PRC127);
+       adapter->stats.prc255 += E1000_READ_REG(hw, PRC255);
+       adapter->stats.prc511 += E1000_READ_REG(hw, PRC511);
+       adapter->stats.prc1023 += E1000_READ_REG(hw, PRC1023);
+       adapter->stats.prc1522 += E1000_READ_REG(hw, PRC1522);
+
+       spin_unlock_irqrestore(&adapter->stats_lock, flags);
+
+       /* the rest of the counters are only modified here */
+
+       adapter->stats.symerrs += E1000_READ_REG(hw, SYMERRS);
+       adapter->stats.mpc += E1000_READ_REG(hw, MPC);
+       adapter->stats.scc += E1000_READ_REG(hw, SCC);
+       adapter->stats.ecol += E1000_READ_REG(hw, ECOL);
+       adapter->stats.mcc += E1000_READ_REG(hw, MCC);
+       adapter->stats.latecol += E1000_READ_REG(hw, LATECOL);
+       adapter->stats.dc += E1000_READ_REG(hw, DC);
+       adapter->stats.sec += E1000_READ_REG(hw, SEC);
+       adapter->stats.rlec += E1000_READ_REG(hw, RLEC);
+       adapter->stats.xonrxc += E1000_READ_REG(hw, XONRXC);
+       adapter->stats.xontxc += E1000_READ_REG(hw, XONTXC);
+       adapter->stats.xoffrxc += E1000_READ_REG(hw, XOFFRXC);
+       adapter->stats.xofftxc += E1000_READ_REG(hw, XOFFTXC);
+       adapter->stats.fcruc += E1000_READ_REG(hw, FCRUC);
+       adapter->stats.gptc += E1000_READ_REG(hw, GPTC);
+       adapter->stats.gotcl += E1000_READ_REG(hw, GOTCL);
+       adapter->stats.gotch += E1000_READ_REG(hw, GOTCH);
+       adapter->stats.rnbc += E1000_READ_REG(hw, RNBC);
+       adapter->stats.ruc += E1000_READ_REG(hw, RUC);
+       adapter->stats.rfc += E1000_READ_REG(hw, RFC);
+       adapter->stats.rjc += E1000_READ_REG(hw, RJC);
+       adapter->stats.torl += E1000_READ_REG(hw, TORL);
+       adapter->stats.torh += E1000_READ_REG(hw, TORH);
+       adapter->stats.totl += E1000_READ_REG(hw, TOTL);
+       adapter->stats.toth += E1000_READ_REG(hw, TOTH);
+       adapter->stats.tpr += E1000_READ_REG(hw, TPR);
+       adapter->stats.ptc64 += E1000_READ_REG(hw, PTC64);
+       adapter->stats.ptc127 += E1000_READ_REG(hw, PTC127);
+       adapter->stats.ptc255 += E1000_READ_REG(hw, PTC255);
+       adapter->stats.ptc511 += E1000_READ_REG(hw, PTC511);
+       adapter->stats.ptc1023 += E1000_READ_REG(hw, PTC1023);
+       adapter->stats.ptc1522 += E1000_READ_REG(hw, PTC1522);
+       adapter->stats.mptc += E1000_READ_REG(hw, MPTC);
+       adapter->stats.bptc += E1000_READ_REG(hw, BPTC);
+
+       /* used for adaptive IFS */
+
+       hw->tx_packet_delta = E1000_READ_REG(hw, TPT);
+       adapter->stats.tpt += hw->tx_packet_delta;
+       hw->collision_delta = E1000_READ_REG(hw, COLC);
+       adapter->stats.colc += hw->collision_delta;
+
+       if(hw->mac_type >= e1000_82543) {
+               adapter->stats.algnerrc += E1000_READ_REG(hw, ALGNERRC);
+               adapter->stats.rxerrc += E1000_READ_REG(hw, RXERRC);
+               adapter->stats.tncrs += E1000_READ_REG(hw, TNCRS);
+               adapter->stats.cexterr += E1000_READ_REG(hw, CEXTERR);
+               adapter->stats.tsctc += E1000_READ_REG(hw, TSCTC);
+               adapter->stats.tsctfc += E1000_READ_REG(hw, TSCTFC);
+       }
+
+       /* Fill out the OS statistics structure */
+
+       adapter->net_stats.rx_packets = adapter->stats.gprc;
+       adapter->net_stats.tx_packets = adapter->stats.gptc;
+       adapter->net_stats.rx_bytes = adapter->stats.gorcl;
+       adapter->net_stats.tx_bytes = adapter->stats.gotcl;
+       adapter->net_stats.multicast = adapter->stats.mprc;
+       adapter->net_stats.collisions = adapter->stats.colc;
+
+       /* Rx Errors */
+
+       adapter->net_stats.rx_errors = adapter->stats.rxerrc +
+               adapter->stats.crcerrs + adapter->stats.algnerrc +
+               adapter->stats.rlec + adapter->stats.rnbc +
+               adapter->stats.mpc + adapter->stats.cexterr;
+       adapter->net_stats.rx_dropped = adapter->stats.rnbc;
+       adapter->net_stats.rx_length_errors = adapter->stats.rlec;
+       adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs;
+       adapter->net_stats.rx_frame_errors = adapter->stats.algnerrc;
+       adapter->net_stats.rx_fifo_errors = adapter->stats.mpc;
+       adapter->net_stats.rx_missed_errors = adapter->stats.mpc;
+
+       /* Tx Errors */
+
+       adapter->net_stats.tx_errors = adapter->stats.ecol +
+                                      adapter->stats.latecol;
+       adapter->net_stats.tx_aborted_errors = adapter->stats.ecol;
+       adapter->net_stats.tx_window_errors = adapter->stats.latecol;
+       adapter->net_stats.tx_carrier_errors = adapter->stats.tncrs;
+
+       /* Tx Dropped needs to be maintained elsewhere */
+
+       /* Phy Stats */
+
+       if(hw->media_type == e1000_media_type_copper) {
+               if((adapter->link_speed == SPEED_1000) &&
+                  (!e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_tmp))) {
+                       phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK;
+                       adapter->phy_stats.idle_errors += phy_tmp;
+               }
+
+               if((hw->mac_type <= e1000_82546) &&
+                  !e1000_read_phy_reg(hw, M88E1000_RX_ERR_CNTR, &phy_tmp))
+                       adapter->phy_stats.receive_errors += phy_tmp;
+       }
+}
+
+/**
+ * e1000_irq_disable - Mask off interrupt generation on the NIC
+ * @adapter: board private structure
+ **/
+
+static inline void
+e1000_irq_disable(struct e1000_adapter *adapter)
+{
+       atomic_inc(&adapter->irq_sem);
+       E1000_WRITE_REG(&adapter->hw, IMC, ~0);
+       E1000_WRITE_FLUSH(&adapter->hw);
+       synchronize_irq();
+}
+
+/**
+ * e1000_irq_enable - Enable default interrupt generation settings
+ * @adapter: board private structure
+ **/
+
+static inline void
+e1000_irq_enable(struct e1000_adapter *adapter)
+{
+       if(atomic_dec_and_test(&adapter->irq_sem)) {
+               E1000_WRITE_REG(&adapter->hw, IMS, IMS_ENABLE_MASK);
+               E1000_WRITE_FLUSH(&adapter->hw);
+       }
+}
+
+/**
+ * e1000_intr - Interrupt Handler
+ * @irq: interrupt number
+ * @data: pointer to a network interface device structure
+ * @pt_regs: CPU registers structure
+ **/
+
+static void
+e1000_intr(int irq, void *data, struct pt_regs *regs)
+{
+       struct net_device *netdev = data;
+       struct e1000_adapter *adapter = netdev->priv;
+       uint32_t icr;
+       int i = E1000_MAX_INTR;
+
+       while(i && (icr = E1000_READ_REG(&adapter->hw, ICR))) {
+
+               if(icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
+                       adapter->hw.get_link_status = 1;
+                       mod_timer(&adapter->watchdog_timer, jiffies);
+               }
+
+               e1000_clean_rx_irq(adapter);
+               e1000_clean_tx_irq(adapter);
+               i--;
+
+       }
+}
+
+/**
+ * e1000_clean_tx_irq - Reclaim resources after transmit completes
+ * @adapter: board private structure
+ **/
+
+static void
+e1000_clean_tx_irq(struct e1000_adapter *adapter)
+{
+       struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
+       struct net_device *netdev = adapter->netdev;
+       struct pci_dev *pdev = adapter->pdev;
+       struct e1000_tx_desc *tx_desc;
+       int i;
+
+       i = tx_ring->next_to_clean;
+       tx_desc = E1000_TX_DESC(*tx_ring, i);
+
+       while(tx_desc->upper.data & cpu_to_le32(E1000_TXD_STAT_DD)) {
+
+               if(tx_ring->buffer_info[i].dma) {
+
+                       pci_unmap_page(pdev,
+                                      tx_ring->buffer_info[i].dma,
+                                      tx_ring->buffer_info[i].length,
+                                      PCI_DMA_TODEVICE);
+
+                       tx_ring->buffer_info[i].dma = 0;
+               }
+
+               if(tx_ring->buffer_info[i].skb) {
+
+                       dev_kfree_skb_any(tx_ring->buffer_info[i].skb);
+
+                       tx_ring->buffer_info[i].skb = NULL;
+               }
+
+               tx_desc->upper.data = 0;
+
+               i = (i + 1) % tx_ring->count;
+               tx_desc = E1000_TX_DESC(*tx_ring, i);
+       }
+
+       tx_ring->next_to_clean = i;
+
+       if(netif_queue_stopped(netdev) && netif_carrier_ok(netdev) &&
+          (E1000_DESC_UNUSED(tx_ring) > E1000_TX_QUEUE_WAKE)) {
+
+               netif_wake_queue(netdev);
+       }
+}
+
+/**
+ * e1000_clean_rx_irq - Send received data up the network stack,
+ * @adapter: board private structure
+ **/
+
+static void
+e1000_clean_rx_irq(struct e1000_adapter *adapter)
+{
+       struct e1000_desc_ring *rx_ring = &adapter->rx_ring;
+       struct net_device *netdev = adapter->netdev;
+       struct pci_dev *pdev = adapter->pdev;
+       struct e1000_rx_desc *rx_desc;
+       struct sk_buff *skb;
+       unsigned long flags;
+       uint32_t length;
+       uint8_t last_byte;
+       int i;
+
+       i = rx_ring->next_to_clean;
+       rx_desc = E1000_RX_DESC(*rx_ring, i);
+
+       while(rx_desc->status & E1000_RXD_STAT_DD) {
+
+               pci_unmap_single(pdev,
+                                rx_ring->buffer_info[i].dma,
+                                rx_ring->buffer_info[i].length,
+                                PCI_DMA_FROMDEVICE);
+
+               skb = rx_ring->buffer_info[i].skb;
+               length = le16_to_cpu(rx_desc->length);
+
+               if(!(rx_desc->status & E1000_RXD_STAT_EOP)) {
+
+                       /* All receives must fit into a single buffer */
+
+                       E1000_DBG("Receive packet consumed multiple buffers\n");
+
+                       dev_kfree_skb_irq(skb);
+                       rx_desc->status = 0;
+                       rx_ring->buffer_info[i].skb = NULL;
+
+                       i = (i + 1) % rx_ring->count;
+
+                       rx_desc = E1000_RX_DESC(*rx_ring, i);
+                       continue;
+               }
+
+               if(rx_desc->errors & E1000_RXD_ERR_FRAME_ERR_MASK) {
+
+                       last_byte = *(skb->data + length - 1);
+
+                       if(TBI_ACCEPT(&adapter->hw, rx_desc->status,
+                                     rx_desc->errors, length, last_byte)) {
+
+                               spin_lock_irqsave(&adapter->stats_lock, flags);
+
+                               e1000_tbi_adjust_stats(&adapter->hw,
+                                                      &adapter->stats,
+                                                      length, skb->data);
+
+                               spin_unlock_irqrestore(&adapter->stats_lock,
+                                                      flags);
+                               length--;
+                       } else {
+
+                               dev_kfree_skb_irq(skb);
+                               rx_desc->status = 0;
+                               rx_ring->buffer_info[i].skb = NULL;
+
+                               i = (i + 1) % rx_ring->count;
+
+                               rx_desc = E1000_RX_DESC(*rx_ring, i);
+                               continue;
+                       }
+               }
+
+               /* Good Receive */
+               skb_put(skb, length - ETHERNET_FCS_SIZE);
+
+               /* Receive Checksum Offload */
+               e1000_rx_checksum(adapter, rx_desc, skb);
+
+               skb->protocol = eth_type_trans(skb, netdev);
+               if(adapter->vlgrp && (rx_desc->status & E1000_RXD_STAT_VP)) {
+                       vlan_hwaccel_rx(skb, adapter->vlgrp,
+                               (rx_desc->special & E1000_RXD_SPC_VLAN_MASK));
+               } else {
+                       netif_rx(skb);
+               }
+               netdev->last_rx = jiffies;
+
+               rx_desc->status = 0;
+               rx_ring->buffer_info[i].skb = NULL;
+
+               i = (i + 1) % rx_ring->count;
+
+               rx_desc = E1000_RX_DESC(*rx_ring, i);
+       }
+
+       rx_ring->next_to_clean = i;
+
+       e1000_alloc_rx_buffers(adapter);
+}
+
+/**
+ * e1000_alloc_rx_buffers - Replace used receive buffers
+ * @data: address of board private structure
+ **/
+
+static void
+e1000_alloc_rx_buffers(struct e1000_adapter *adapter)
+{
+       struct e1000_desc_ring *rx_ring = &adapter->rx_ring;
+       struct net_device *netdev = adapter->netdev;
+       struct pci_dev *pdev = adapter->pdev;
+       struct e1000_rx_desc *rx_desc;
+       struct sk_buff *skb;
+       int reserve_len;
+       int i;
+
+       reserve_len = 2;
+
+       i = rx_ring->next_to_use;
+
+       while(!rx_ring->buffer_info[i].skb) {
+               rx_desc = E1000_RX_DESC(*rx_ring, i);
+
+               skb = dev_alloc_skb(adapter->rx_buffer_len + reserve_len);
+
+               if(!skb) {
+                       /* Better luck next round */
+                       break;
+               }
+
+               /* Make buffer alignment 2 beyond a 16 byte boundary
+                * this will result in a 16 byte aligned IP header after
+                * the 14 byte MAC header is removed
+                */
+               skb_reserve(skb, reserve_len);
+
+               skb->dev = netdev;
+
+               rx_ring->buffer_info[i].skb = skb;
+               rx_ring->buffer_info[i].length = adapter->rx_buffer_len;
+               rx_ring->buffer_info[i].dma =
+                       pci_map_single(pdev,
+                                      skb->data,
+                                      adapter->rx_buffer_len,
+                                      PCI_DMA_FROMDEVICE);
+
+               rx_desc->buffer_addr = cpu_to_le64(rx_ring->buffer_info[i].dma);
+
+               if(!(i % E1000_RX_BUFFER_WRITE)) {
+                       /* Force memory writes to complete before letting h/w
+                        * know there are new descriptors to fetch.  (Only
+                        * applicable for weak-ordered memory model archs,
+                        * such as IA-64). */
+                       wmb();
+
+                       E1000_WRITE_REG(&adapter->hw, RDT, i);
+               }
+
+               i = (i + 1) % rx_ring->count;
+       }
+
+       rx_ring->next_to_use = i;
+}
+
+/**
+ * e1000_ioctl -
+ * @netdev:
+ * @ifreq:
+ * @cmd:
+ **/
+
+static int
+e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+       switch (cmd) {
+       case SIOCETHTOOL:
+               return e1000_ethtool_ioctl(netdev, ifr);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+/**
+ * e1000_rx_checksum - Receive Checksum Offload for 82543
+ * @adapter: board private structure
+ * @rx_desc: receive descriptor
+ * @sk_buff: socket buffer with received data
+ **/
+
+static inline void
+e1000_rx_checksum(struct e1000_adapter *adapter,
+                  struct e1000_rx_desc *rx_desc,
+                  struct sk_buff *skb)
+{
+       /* 82543 or newer only */
+       if((adapter->hw.mac_type < e1000_82543) ||
+       /* Ignore Checksum bit is set */
+       (rx_desc->status & E1000_RXD_STAT_IXSM) ||
+       /* TCP Checksum has not been calculated */
+       (!(rx_desc->status & E1000_RXD_STAT_TCPCS))) {
+               skb->ip_summed = CHECKSUM_NONE;
+               return;
+       }
+
+       /* At this point we know the hardware did the TCP checksum */
+       /* now look at the TCP checksum error bit */
+       if(rx_desc->errors & E1000_RXD_ERR_TCPE) {
+               /* let the stack verify checksum errors */
+               skb->ip_summed = CHECKSUM_NONE;
+               adapter->hw_csum_err++;
+       } else {
+       /* TCP checksum is good */
+               skb->ip_summed = CHECKSUM_UNNECESSARY;
+               adapter->hw_csum_good++;
+       }
+}
+
+void
+e1000_pci_set_mwi(struct e1000_hw *hw)
+{
+       struct e1000_adapter *adapter = hw->back;
+
+       pci_set_mwi(adapter->pdev);
+}
+
+void
+e1000_pci_clear_mwi(struct e1000_hw *hw)
+{
+       struct e1000_adapter *adapter = hw->back;
+
+       pci_clear_mwi(adapter->pdev);
+}
+
+void
+e1000_read_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t *value)
+{
+       struct e1000_adapter *adapter = hw->back;
+
+       pci_read_config_word(adapter->pdev, reg, value);
+}
+
+void
+e1000_write_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t *value)
+{
+       struct e1000_adapter *adapter = hw->back;
+
+       pci_write_config_word(adapter->pdev, reg, *value);
+}
+
+uint32_t
+e1000_io_read(struct e1000_hw *hw, uint32_t port)
+{
+       return inl(port);
+}
+
+void
+e1000_io_write(struct e1000_hw *hw, uint32_t port, uint32_t value)
+{
+       outl(value, port);
+}
+
+static void
+e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
+{
+       struct e1000_adapter *adapter = netdev->priv;
+       uint32_t ctrl, rctl;
+
+       e1000_irq_disable(adapter);
+       adapter->vlgrp = grp;
+
+       if(grp) {
+               /* enable VLAN tag insert/strip */
+
+               E1000_WRITE_REG(&adapter->hw, VET, ETHERNET_IEEE_VLAN_TYPE);
+
+               ctrl = E1000_READ_REG(&adapter->hw, CTRL);
+               ctrl |= E1000_CTRL_VME;
+               E1000_WRITE_REG(&adapter->hw, CTRL, ctrl);
+
+               /* enable VLAN receive filtering */
+
+               rctl = E1000_READ_REG(&adapter->hw, RCTL);
+               rctl |= E1000_RCTL_VFE;
+               rctl &= ~E1000_RCTL_CFIEN;
+               E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
+       } else {
+               /* disable VLAN tag insert/strip */
+
+               ctrl = E1000_READ_REG(&adapter->hw, CTRL);
+               ctrl &= ~E1000_CTRL_VME;
+               E1000_WRITE_REG(&adapter->hw, CTRL, ctrl);
+
+               /* disable VLAN filtering */
+
+               rctl = E1000_READ_REG(&adapter->hw, RCTL);
+               rctl &= ~E1000_RCTL_VFE;
+               E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
+       }
+
+       e1000_irq_enable(adapter);
+}
+
+static void
+e1000_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid)
+{
+       struct e1000_adapter *adapter = netdev->priv;
+       uint32_t vfta, index;
+
+       /* add VID to filter table */
+
+       index = (vid >> 5) & 0x7F;
+       vfta = E1000_READ_REG_ARRAY(&adapter->hw, VFTA, index);
+       vfta |= (1 << (vid & 0x1F));
+       e1000_write_vfta(&adapter->hw, index, vfta);
+}
+
+static void
+e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid)
+{
+       struct e1000_adapter *adapter = netdev->priv;
+       uint32_t vfta, index;
+
+       e1000_irq_disable(adapter);
+
+       if(adapter->vlgrp)
+               adapter->vlgrp->vlan_devices[vid] = NULL;
+
+       e1000_irq_enable(adapter);
+
+       /* remove VID from filter table*/
+
+       index = (vid >> 5) & 0x7F;
+       vfta = E1000_READ_REG_ARRAY(&adapter->hw, VFTA, index);
+       vfta &= ~(1 << (vid & 0x1F));
+       e1000_write_vfta(&adapter->hw, index, vfta);
+}
+
+static void
+e1000_restore_vlan(struct e1000_adapter *adapter)
+{
+       e1000_vlan_rx_register(adapter->netdev, adapter->vlgrp);
+
+       if(adapter->vlgrp) {
+               uint16_t vid;
+               for(vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) {
+                       if(!adapter->vlgrp->vlan_devices[vid])
+                               continue;
+                       e1000_vlan_rx_add_vid(adapter->netdev, vid);
+               }
+       }
+}
+
+static int
+e1000_notify_reboot(struct notifier_block *nb, unsigned long event, void *p)
+{
+       struct pci_dev *pdev = NULL;
+
+       switch(event) {
+       case SYS_DOWN:
+       case SYS_HALT:
+       case SYS_POWER_OFF:
+               pci_for_each_dev(pdev) {
+                       if(pci_dev_driver(pdev) == &e1000_driver)
+                               e1000_suspend(pdev, 3);
+               }
+       }
+       return NOTIFY_DONE;
+}
+
+static int
+e1000_suspend(struct pci_dev *pdev, uint32_t state)
+{
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct e1000_adapter *adapter = netdev->priv;
+       uint32_t ctrl, ctrl_ext, rctl, manc, status;
+       uint32_t wufc = adapter->wol;
+
+       netif_device_detach(netdev);
+
+       if(netif_running(netdev))
+               e1000_down(adapter);
+
+       status = E1000_READ_REG(&adapter->hw, STATUS);
+       if(status & E1000_STATUS_LU)
+               wufc &= ~E1000_WUFC_LNKC;
+
+       if(wufc) {
+               e1000_setup_rctl(adapter);
+               e1000_set_multi(netdev);
+
+               /* turn on all-multi mode if wake on multicast is enabled */
+               if(adapter->wol & E1000_WUFC_MC) {
+                       rctl = E1000_READ_REG(&adapter->hw, RCTL);
+                       rctl |= E1000_RCTL_MPE;
+                       E1000_WRITE_REG(&adapter->hw, RCTL, rctl);
+               }
+
+               if(adapter->hw.mac_type >= e1000_82540) {
+                       ctrl = E1000_READ_REG(&adapter->hw, CTRL);
+                       /* advertise wake from D3Cold */
+                       #define E1000_CTRL_ADVD3WUC 0x00100000
+                       /* phy power management enable */
+                       #define E1000_CTRL_EN_PHY_PWR_MGMT 0x00200000
+                       ctrl |= E1000_CTRL_ADVD3WUC |
+                               E1000_CTRL_EN_PHY_PWR_MGMT;
+                       E1000_WRITE_REG(&adapter->hw, CTRL, ctrl);
+               }
+
+               if(adapter->hw.media_type == e1000_media_type_fiber) {
+                       /* keep the laser running in D3 */
+                       ctrl_ext = E1000_READ_REG(&adapter->hw, CTRL_EXT);
+                       ctrl_ext |= E1000_CTRL_EXT_SDP7_DATA;
+                       E1000_WRITE_REG(&adapter->hw, CTRL_EXT, ctrl_ext);
+               }
+
+               E1000_WRITE_REG(&adapter->hw, WUC, E1000_WUC_PME_EN);
+               E1000_WRITE_REG(&adapter->hw, WUFC, wufc);
+               pci_enable_wake(pdev, 3, 1);
+               pci_enable_wake(pdev, 4, 1); /* 4 == D3 cold */
+       } else {
+               E1000_WRITE_REG(&adapter->hw, WUC, 0);
+               E1000_WRITE_REG(&adapter->hw, WUFC, 0);
+               pci_enable_wake(pdev, 3, 0);
+               pci_enable_wake(pdev, 4, 0); /* 4 == D3 cold */
+       }
+
+       pci_save_state(pdev, adapter->pci_state);
+
+       if(adapter->hw.mac_type >= e1000_82540) {
+               manc = E1000_READ_REG(&adapter->hw, MANC);
+               if(manc & E1000_MANC_SMBUS_EN) {
+                       manc |= E1000_MANC_ARP_EN;
+                       E1000_WRITE_REG(&adapter->hw, MANC, manc);
+                       state = 0;
+               }
+       }
+
+       state = (state > 0) ? 3 : 0;
+       pci_set_power_state(pdev, state);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int
+e1000_resume(struct pci_dev *pdev)
+{
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct e1000_adapter *adapter = netdev->priv;
+       uint32_t manc;
+
+       pci_set_power_state(pdev, 0);
+       pci_restore_state(pdev, adapter->pci_state);
+
+       pci_enable_wake(pdev, 3, 0);
+       pci_enable_wake(pdev, 4, 0); /* 4 == D3 cold */
+
+       e1000_reset(adapter);
+       E1000_WRITE_REG(&adapter->hw, WUS, ~0);
+
+       if(netif_running(netdev))
+               e1000_up(adapter);
+
+       netif_device_attach(netdev);
+
+       if(adapter->hw.mac_type >= e1000_82540) {
+               manc = E1000_READ_REG(&adapter->hw, MANC);
+               manc &= ~(E1000_MANC_ARP_EN);
+               E1000_WRITE_REG(&adapter->hw, MANC, manc);
+       }
+
+       return 0;
+}
+#endif
+
+/* e1000_main.c */
diff --git a/xen-2.4.16/drivers/net/e1000/e1000_osdep.h b/xen-2.4.16/drivers/net/e1000/e1000_osdep.h
new file mode 100644 (file)
index 0000000..e51e083
--- /dev/null
@@ -0,0 +1,114 @@
+/*******************************************************************************
+
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  This program is free software; you can redistribute it and/or modify it 
+  under the terms of the GNU General Public License as published by the Free 
+  Software Foundation; either version 2 of the License, or (at your option) 
+  any later version.
+  
+  This program is distributed in the hope that it will be useful, but WITHOUT 
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+  more details.
+  
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59 
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+
+/* glue for the OS independant part of e1000
+ * includes register access macros
+ */
+
+#ifndef _E1000_OSDEP_H_
+#define _E1000_OSDEP_H_
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+
+#ifndef msec_delay
+#define msec_delay(x) {\
+       int s=jiffies+1+((x*HZ)/1000); \
+       printk("mdelay(%d) called -- spin\n",x); \
+       while(jiffies<s); printk("mdelay over\n");}
+
+#if 0
+/********************  NOT in XEN ! *******/
+#define XXXXmsec_delay(x)      do { if(in_interrupt()) { \
+                               /* Don't mdelay in interrupt context! */ \
+                               BUG(); \
+                       } else { \
+                               set_current_state(TASK_UNINTERRUPTIBLE); \
+                               schedule_timeout((x * HZ)/1000); \
+                       } } while(0)
+#endif
+
+#else
+#error "msec already defined!"
+#endif
+
+#define PCI_COMMAND_REGISTER   PCI_COMMAND
+#define CMD_MEM_WRT_INVALIDATE PCI_COMMAND_INVALIDATE
+
+typedef enum {
+    FALSE = 0,
+    TRUE = 1
+} boolean_t;
+
+#define ASSERT(x)      if(!(x)) BUG()
+#define MSGOUT(S, A, B)        printk(KERN_DEBUG S "\n", A, B)
+
+#define DBG 1
+
+#if DBG
+#define DEBUGOUT(S)            printk(KERN_DEBUG S "\n")
+#define DEBUGOUT1(S, A...)     printk(KERN_DEBUG S "\n", A)
+#else
+#define DEBUGOUT(S)
+#define DEBUGOUT1(S, A...)
+#endif
+
+#define DEBUGFUNC(F) DEBUGOUT(F)
+#define DEBUGOUT2 DEBUGOUT1
+#define DEBUGOUT3 DEBUGOUT2
+#define DEBUGOUT7 DEBUGOUT3
+
+
+#define E1000_WRITE_REG(a, reg, value) ( \
+    ((a)->mac_type >= e1000_82543) ? \
+        (writel((value), ((a)->hw_addr + E1000_##reg))) : \
+        (writel((value), ((a)->hw_addr + E1000_82542_##reg))))
+
+#define E1000_READ_REG(a, reg) ( \
+    ((a)->mac_type >= e1000_82543) ? \
+        readl((a)->hw_addr + E1000_##reg) : \
+        readl((a)->hw_addr + E1000_82542_##reg))
+
+#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) ( \
+    ((a)->mac_type >= e1000_82543) ? \
+        writel((value), ((a)->hw_addr + E1000_##reg + ((offset) << 2))) : \
+        writel((value), ((a)->hw_addr + E1000_82542_##reg + ((offset) << 2))))
+
+#define E1000_READ_REG_ARRAY(a, reg, offset) ( \
+    ((a)->mac_type >= e1000_82543) ? \
+        readl((a)->hw_addr + E1000_##reg + ((offset) << 2)) : \
+        readl((a)->hw_addr + E1000_82542_##reg + ((offset) << 2)))
+
+#define E1000_WRITE_FLUSH(a) E1000_READ_REG(a, STATUS)
+
+#endif /* _E1000_OSDEP_H_ */
diff --git a/xen-2.4.16/drivers/net/e1000/e1000_param.c b/xen-2.4.16/drivers/net/e1000/e1000_param.c
new file mode 100644 (file)
index 0000000..a11941f
--- /dev/null
@@ -0,0 +1,655 @@
+/*******************************************************************************
+
+  
+  Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved.
+  
+  This program is free software; you can redistribute it and/or modify it 
+  under the terms of the GNU General Public License as published by the Free 
+  Software Foundation; either version 2 of the License, or (at your option) 
+  any later version.
+  
+  This program is distributed in the hope that it will be useful, but WITHOUT 
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
+  more details.
+  
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59 
+  Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+  
+  The full GNU General Public License is included in this distribution in the
+  file called LICENSE.
+  
+  Contact Information:
+  Linux NICS <linux.nics@intel.com>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include "e1000.h"
+
+/* This is the only thing that needs to be changed to adjust the
+ * maximum number of ports that the driver can manage.
+ */
+
+#define E1000_MAX_NIC 32
+
+#define OPTION_UNSET    -1
+#define OPTION_DISABLED 0
+#define OPTION_ENABLED  1
+
+/* Module Parameters are always initialized to -1, so that the driver
+ * can tell the difference between no user specified value or the
+ * user asking for the default value.
+ * The true default values are loaded in when e1000_check_options is called.
+ *
+ * This is a GCC extension to ANSI C.
+ * See the item "Labeled Elements in Initializers" in the section
+ * "Extensions to the C Language Family" of the GCC documentation.
+ */
+
+#define E1000_PARAM_INIT { [0 ... E1000_MAX_NIC] = OPTION_UNSET }
+
+/* All parameters are treated the same, as an integer array of values.
+ * This macro just reduces the need to repeat the same declaration code
+ * over and over (plus this helps to avoid typo bugs).
+ */
+
+#define E1000_PARAM(X, S) \
+static const int __devinitdata X[E1000_MAX_NIC + 1] = E1000_PARAM_INIT; \
+MODULE_PARM(X, "1-" __MODULE_STRING(E1000_MAX_NIC) "i"); \
+MODULE_PARM_DESC(X, S);
+
+/* Transmit Descriptor Count
+ *
+ * Valid Range: 80-256 for 82542 and 82543 gigabit ethernet controllers
+ * Valid Range: 80-4096 for 82544
+ *
+ * Default Value: 256
+ */
+
+E1000_PARAM(TxDescriptors, "Number of transmit descriptors");
+
+/* Receive Descriptor Count
+ *
+ * Valid Range: 80-256 for 82542 and 82543 gigabit ethernet controllers
+ * Valid Range: 80-4096 for 82544
+ *
+ * Default Value: 80
+ */
+
+E1000_PARAM(RxDescriptors, "Number of receive descriptors");
+
+/* User Specified Speed Override
+ *
+ * Valid Range: 0, 10, 100, 1000
+ *  - 0    - auto-negotiate at all supported speeds
+ *  - 10   - only link at 10 Mbps
+ *  - 100  - only link at 100 Mbps
+ *  - 1000 - only link at 1000 Mbps
+ *
+ * Default Value: 0
+ */
+
+E1000_PARAM(Speed, "Speed setting");
+
+/* User Specified Duplex Override
+ *
+ * Valid Range: 0-2
+ *  - 0 - auto-negotiate for duplex
+ *  - 1 - only link at half duplex
+ *  - 2 - only link at full duplex
+ *
+ * Default Value: 0
+ */
+
+E1000_PARAM(Duplex, "Duplex setting");
+
+/* Auto-negotiation Advertisement Override
+ *
+ * Valid Range: 0x01-0x0F, 0x20-0x2F
+ *
+ * The AutoNeg value is a bit mask describing which speed and duplex
+ * combinations should be advertised during auto-negotiation.
+ * The supported speed and duplex modes are listed below
+ *
+ * Bit           7     6     5      4      3     2     1      0
+ * Speed (Mbps)  N/A   N/A   1000   N/A    100   100   10     10
+ * Duplex                    Full          Full  Half  Full   Half
+ *
+ * Default Value: 0x2F
+ */
+
+E1000_PARAM(AutoNeg, "Advertised auto-negotiation setting");
+
+/* User Specified Flow Control Override
+ *
+ * Valid Range: 0-3
+ *  - 0 - No Flow Control
+ *  - 1 - Rx only, respond to PAUSE frames but do not generate them
+ *  - 2 - Tx only, generate PAUSE frames but ignore them on receive
+ *  - 3 - Full Flow Control Support
+ *
+ * Default Value: Read flow control settings from the EEPROM
+ */
+
+E1000_PARAM(FlowControl, "Flow Control setting");
+
+/* XsumRX - Receive Checksum Offload Enable/Disable
+ *
+ * Valid Range: 0, 1
+ *  - 0 - disables all checksum offload
+ *  - 1 - enables receive IP/TCP/UDP checksum offload
+ *        on 82543 based NICs
+ *
+ * Default Value: 1
+ */
+
+E1000_PARAM(XsumRX, "Disable or enable Receive Checksum offload");
+
+/* Transmit Interrupt Delay in units of 1.024 microseconds
+ *
+ * Valid Range: 0-65535
+ *
+ * Default Value: 64
+ */
+
+E1000_PARAM(TxIntDelay, "Transmit Interrupt Delay");
+
+/* Transmit Absolute Interrupt Delay in units of 1.024 microseconds
+ *
+ * Valid Range: 0-65535
+ *
+ * Default Value: 0
+ */
+
+E1000_PARAM(TxAbsIntDelay, "Transmit Absolute Interrupt Delay");
+
+/* Receive Interrupt Delay in units of 1.024 microseconds
+ *
+ * Valid Range: 0-65535
+ *
+ * Default Value: 0/128
+ */
+
+E1000_PARAM(RxIntDelay, "Receive Interrupt Delay");
+
+/* Receive Absolute Interrupt Delay in units of 1.024 microseconds
+ *
+ * Valid Range: 0-65535
+ *
+ * Default Value: 128
+ */
+
+E1000_PARAM(RxAbsIntDelay, "Receive Absolute Interrupt Delay");
+
+#define AUTONEG_ADV_DEFAULT  0x2F
+#define AUTONEG_ADV_MASK     0x2F
+#define FLOW_CONTROL_DEFAULT FLOW_CONTROL_FULL
+
+#define DEFAULT_TXD                  256
+#define MAX_TXD                      256
+#define MIN_TXD                       80
+#define MAX_82544_TXD               4096
+
+#define DEFAULT_RXD                   80
+#define MAX_RXD                      256
+#define MIN_RXD                       80
+#define MAX_82544_RXD               4096
+
+#define DEFAULT_RDTR                   0
+#define MAX_RXDELAY               0xFFFF
+#define MIN_RXDELAY                    0
+
+#define DEFAULT_RADV                 128
+#define MAX_RXABSDELAY            0xFFFF
+#define MIN_RXABSDELAY                 0
+
+#define DEFAULT_TIDV                  64
+#define MAX_TXDELAY               0xFFFF
+#define MIN_TXDELAY                    0
+
+#define DEFAULT_TADV                  64
+#define MAX_TXABSDELAY            0xFFFF
+#define MIN_TXABSDELAY                 0
+
+struct e1000_option {
+       enum { enable_option, range_option, list_option } type;
+       char *name;
+       char *err;
+       int  def;
+       union {
+               struct { /* range_option info */
+                       int min;
+                       int max;
+               } r;
+               struct { /* list_option info */
+                       int nr;
+                       struct e1000_opt_list { int i; char *str; } *p;
+               } l;
+       } arg;
+};
+
+static int __devinit
+e1000_validate_option(int *value, struct e1000_option *opt)
+{
+       if(*value == OPTION_UNSET) {
+               *value = opt->def;
+               return 0;
+       }
+
+       switch (opt->type) {
+       case enable_option:
+               switch (*value) {
+               case OPTION_ENABLED:
+                       printk(KERN_INFO "%s Enabled\n", opt->name);
+                       return 0;
+               case OPTION_DISABLED:
+                       printk(KERN_INFO "%s Disabled\n", opt->name);
+                       return 0;
+               }
+               break;
+       case range_option:
+               if(*value >= opt->arg.r.min && *value <= opt->arg.r.max) {
+                       printk(KERN_INFO "%s set to %i\n", opt->name, *value);
+                       return 0;
+               }
+               break;
+       case list_option: {
+               int i;
+               struct e1000_opt_list *ent;
+
+               for(i = 0; i < opt->arg.l.nr; i++) {
+                       ent = &opt->arg.l.p[i];
+                       if(*value == ent->i) {
+                               if(ent->str[0] != '\0')
+                                       printk(KERN_INFO "%s\n", ent->str);
+                               return 0;
+                       }
+               }
+       }
+               break;
+       default:
+               BUG();
+       }
+
+       printk(KERN_INFO "Invalid %s specified (%i) %s\n",
+              opt->name, *value, opt->err);
+       *value = opt->def;
+       return -1;
+}
+
+static void e1000_check_fiber_options(struct e1000_adapter *adapter);
+static void e1000_check_copper_options(struct e1000_adapter *adapter);
+
+/**
+ * e1000_check_options - Range Checking for Command Line Parameters
+ * @adapter: board private structure
+ *
+ * This routine checks all command line paramters for valid user
+ * input.  If an invalid value is given, or if no user specified
+ * value exists, a default value is used.  The final value is stored
+ * in a variable in the adapter structure.
+ **/
+
+void __devinit
+e1000_check_options(struct e1000_adapter *adapter)
+{
+       int bd = adapter->bd_number;
+       if(bd >= E1000_MAX_NIC) {
+               printk(KERN_NOTICE
+                      "Warning: no configuration for board #%i\n", bd);
+               printk(KERN_NOTICE "Using defaults for all values\n");
+               bd = E1000_MAX_NIC;
+       }
+
+       { /* Transmit Descriptor Count */
+               struct e1000_option opt = {
+                       .type = range_option,
+                       .name = "Transmit Descriptors",
+                       .err  = "using default of " __MODULE_STRING(DEFAULT_TXD),
+                       .def  = DEFAULT_TXD,
+                       .arg  = { .r = { .min = MIN_TXD }}
+               };
+               struct e1000_desc_ring *tx_ring = &adapter->tx_ring;
+               e1000_mac_type mac_type = adapter->hw.mac_type;
+               opt.arg.r.max = mac_type < e1000_82544 ?
+                       MAX_TXD : MAX_82544_TXD;
+
+               tx_ring->count = TxDescriptors[bd];
+               e1000_validate_option(&tx_ring->count, &opt);
+               E1000_ROUNDUP(tx_ring->count, REQ_TX_DESCRIPTOR_MULTIPLE);
+       }
+       { /* Receive Descriptor Count */
+               struct e1000_option opt = {
+                       .type = range_option,
+                       .name = "Receive Descriptors",
+                       .err  = "using default of " __MODULE_STRING(DEFAULT_RXD),
+                       .def  = DEFAULT_RXD,
+                       .arg  = { .r = { .min = MIN_RXD }}
+               };
+               struct e1000_desc_ring *rx_ring = &adapter->rx_ring;
+               e1000_mac_type mac_type = adapter->hw.mac_type;
+               opt.arg.r.max = mac_type < e1000_82544 ? MAX_RXD : MAX_82544_RXD;
+
+               rx_ring->count = RxDescriptors[bd];
+               e1000_validate_option(&rx_ring->count, &opt);
+               E1000_ROUNDUP(rx_ring->count, REQ_RX_DESCRIPTOR_MULTIPLE);
+       }
+       { /* Checksum Offload Enable/Disable */
+               struct e1000_option opt = {
+                       .type = enable_option,
+                       .name = "Checksum Offload",
+                       .err  = "defaulting to Enabled",
+                       .def  = OPTION_ENABLED
+               };
+
+               int rx_csum = XsumRX[bd];
+               e1000_validate_option(&rx_csum, &opt);
+               adapter->rx_csum = rx_csum;
+       }
+       { /* Flow Control */
+
+               struct e1000_opt_list fc_list[] =
+                       {{ e1000_fc_none,    "Flow Control Disabled" },
+                        { e1000_fc_rx_pause,"Flow Control Receive Only" },
+                        { e1000_fc_tx_pause,"Flow Control Transmit Only" },
+                        { e1000_fc_full,    "Flow Control Enabled" },
+                        { e1000_fc_default, "Flow Control Hardware Default" }};
+
+               struct e1000_option opt = {
+                       .type = list_option,
+                       .name = "Flow Control",
+                       .err  = "reading default settings from EEPROM",
+                       .def  = e1000_fc_default,
+                       .arg  = { .l = { .nr = ARRAY_SIZE(fc_list), .p = fc_list }}
+               };
+
+               int fc = FlowControl[bd];
+               e1000_validate_option(&fc, &opt);
+               adapter->hw.fc = adapter->hw.original_fc = fc;
+       }
+       { /* Transmit Interrupt Delay */
+               char *tidv = "using default of " __MODULE_STRING(DEFAULT_TIDV);
+               struct e1000_option opt = {
+                       .type = range_option,
+                       .name = "Transmit Interrupt Delay",
+                       .arg  = { .r = { .min = MIN_TXDELAY, .max = MAX_TXDELAY }}
+               };
+               opt.def = DEFAULT_TIDV;
+               opt.err = tidv;
+
+               adapter->tx_int_delay = TxIntDelay[bd];
+               e1000_validate_option(&adapter->tx_int_delay, &opt);
+       }
+       { /* Transmit Absolute Interrupt Delay */
+               char *tadv = "using default of " __MODULE_STRING(DEFAULT_TADV);
+               struct e1000_option opt = {
+                       .type = range_option,
+                       .name = "Transmit Absolute Interrupt Delay",
+                       .arg  = { .r = { .min = MIN_TXABSDELAY, .max = MAX_TXABSDELAY }}
+               };
+               opt.def = DEFAULT_TADV;
+               opt.err = tadv;
+
+               adapter->tx_abs_int_delay = TxAbsIntDelay[bd];
+               e1000_validate_option(&adapter->tx_abs_int_delay, &opt);
+       }
+       { /* Receive Interrupt Delay */
+               char *rdtr = "using default of " __MODULE_STRING(DEFAULT_RDTR);
+               struct e1000_option opt = {
+                       .type = range_option,
+                       .name = "Receive Interrupt Delay",
+                       .arg  = { .r = { .min = MIN_RXDELAY, .max = MAX_RXDELAY }}
+               };
+               opt.def = DEFAULT_RDTR;
+               opt.err = rdtr;
+
+               adapter->rx_int_delay = RxIntDelay[bd];
+               e1000_validate_option(&adapter->rx_int_delay, &opt);
+       }
+       { /* Receive Absolute Interrupt Delay */
+               char *radv = "using default of " __MODULE_STRING(DEFAULT_RADV);
+               struct e1000_option opt = {
+                       .type = range_option,
+                       .name = "Receive Absolute Interrupt Delay",
+                       .arg  = { .r = { .min = MIN_RXABSDELAY, .max = MAX_RXABSDELAY }}
+               };
+               opt.def = DEFAULT_RADV;
+               opt.err = radv;
+
+               adapter->rx_abs_int_delay = RxAbsIntDelay[bd];
+               e1000_validate_option(&adapter->rx_abs_int_delay, &opt);
+       }
+       
+       switch(adapter->hw.media_type) {
+       case e1000_media_type_fiber:
+               e1000_check_fiber_options(adapter);
+               break;
+       case e1000_media_type_copper:
+               e1000_check_copper_options(adapter);
+               break;
+       default:
+               BUG();
+       }
+}
+
+/**
+ * e1000_check_fiber_options - Range Checking for Link Options, Fiber Version
+ * @adapter: board private structure
+ *
+ * Handles speed and duplex options on fiber adapters
+ **/
+
+static void __devinit
+e1000_check_fiber_options(struct e1000_adapter *adapter)
+{
+       int bd = adapter->bd_number;
+       bd = bd > E1000_MAX_NIC ? E1000_MAX_NIC : bd;
+
+       if((Speed[bd] != OPTION_UNSET)) {
+               printk(KERN_INFO "Speed not valid for fiber adapters, "
+                      "parameter ignored\n");
+       }
+       if((Duplex[bd] != OPTION_UNSET)) {
+               printk(KERN_INFO "Duplex not valid for fiber adapters, "
+                      "parameter ignored\n");
+       }
+       if((AutoNeg[bd] != OPTION_UNSET)) {
+               printk(KERN_INFO "AutoNeg not valid for fiber adapters, "
+                      "parameter ignored\n");
+       }
+}
+
+/**
+ * e1000_check_copper_options - Range Checking for Link Options, Copper Version
+ * @adapter: board private structure
+ *
+ * Handles speed and duplex options on copper adapters
+ **/
+
+static void __devinit
+e1000_check_copper_options(struct e1000_adapter *adapter)
+{
+       int speed, dplx;
+       int bd = adapter->bd_number;
+       bd = bd > E1000_MAX_NIC ? E1000_MAX_NIC : bd;
+
+       { /* Speed */
+               struct e1000_opt_list speed_list[] = {{          0, "" },
+                                                     {   SPEED_10, "" },
+                                                     {  SPEED_100, "" },
+                                                     { SPEED_1000, "" }};
+
+               struct e1000_option opt = {
+                       .type = list_option,
+                       .name = "Speed",
+                       .err  = "parameter ignored",
+                       .def  = 0,
+                       .arg  = { .l = { .nr = ARRAY_SIZE(speed_list), .p = speed_list }}
+               };
+
+               speed = Speed[bd];
+               e1000_validate_option(&speed, &opt);
+       }
+       { /* Duplex */
+               struct e1000_opt_list dplx_list[] = {{           0, "" },
+                                                    { HALF_DUPLEX, "" },
+                                                    { FULL_DUPLEX, "" }};
+
+               struct e1000_option opt = {
+                       .type = list_option,
+                       .name = "Duplex",
+                       .err  = "parameter ignored",
+                       .def  = 0,
+                       .arg  = { .l = { .nr = ARRAY_SIZE(dplx_list), .p = dplx_list }}
+               };
+
+               dplx = Duplex[bd];
+               e1000_validate_option(&dplx, &opt);
+       }
+
+       if(AutoNeg[bd] != OPTION_UNSET && (speed != 0 || dplx != 0)) {
+               printk(KERN_INFO
+                      "AutoNeg specified along with Speed or Duplex, "
+                      "parameter ignored\n");
+               adapter->hw.autoneg_advertised = AUTONEG_ADV_DEFAULT;
+       } else { /* Autoneg */
+               struct e1000_opt_list an_list[] =
+                       #define AA "AutoNeg advertising "
+                       {{ 0x01, AA "10/HD" },
+                        { 0x02, AA "10/FD" },
+                        { 0x03, AA "10/FD, 10/HD" },
+                        { 0x04, AA "100/HD" },
+                        { 0x05, AA "100/HD, 10/HD" },
+                        { 0x06, AA "100/HD, 10/FD" },
+                        { 0x07, AA "100/HD, 10/FD, 10/HD" },
+                        { 0x08, AA "100/FD" },
+                        { 0x09, AA "100/FD, 10/HD" },
+                        { 0x0a, AA "100/FD, 10/FD" },
+                        { 0x0b, AA "100/FD, 10/FD, 10/HD" },
+                        { 0x0c, AA "100/FD, 100/HD" },
+                        { 0x0d, AA "100/FD, 100/HD, 10/HD" },
+                        { 0x0e, AA "100/FD, 100/HD, 10/FD" },
+                        { 0x0f, AA "100/FD, 100/HD, 10/FD, 10/HD" },
+                        { 0x20, AA "1000/FD" },
+                        { 0x21, AA "1000/FD, 10/HD" },
+                        { 0x22, AA "1000/FD, 10/FD" },
+                        { 0x23, AA "1000/FD, 10/FD, 10/HD" },
+                        { 0x24, AA "1000/FD, 100/HD" },
+                        { 0x25, AA "1000/FD, 100/HD, 10/HD" },
+                        { 0x26, AA "1000/FD, 100/HD, 10/FD" },
+                        { 0x27, AA "1000/FD, 100/HD, 10/FD, 10/HD" },
+                        { 0x28, AA "1000/FD, 100/FD" },
+                        { 0x29, AA "1000/FD, 100/FD, 10/HD" },
+                        { 0x2a, AA "1000/FD, 100/FD, 10/FD" },
+                        { 0x2b, AA "1000/FD, 100/FD, 10/FD, 10/HD" },
+                        { 0x2c, AA "1000/FD, 100/FD, 100/HD" },
+                        { 0x2d, AA "1000/FD, 100/FD, 100/HD, 10/HD" },
+                        { 0x2e, AA "1000/FD, 100/FD, 100/HD, 10/FD" },
+                        { 0x2f, AA "1000/FD, 100/FD, 100/HD, 10/FD, 10/HD" }};
+
+               struct e1000_option opt = {
+                       .type = list_option,
+                       .name = "AutoNeg",
+                       .err  = "parameter ignored",
+                       .def  = AUTONEG_ADV_DEFAULT,
+                       .arg  = { .l = { .nr = ARRAY_SIZE(an_list), .p = an_list }}
+               };
+
+               int an = AutoNeg[bd];
+               e1000_validate_option(&an, &opt);
+               adapter->hw.autoneg_advertised = an;
+       }
+
+       switch (speed + dplx) {
+       case 0:
+               adapter->hw.autoneg = 1;
+               if(Speed[bd] != OPTION_UNSET || Duplex[bd] != OPTION_UNSET)
+                       printk(KERN_INFO
+                              "Speed and duplex autonegotiation enabled\n");
+               break;
+       case HALF_DUPLEX:
+               printk(KERN_INFO "Half Duplex specified without Speed\n");
+               printk(KERN_INFO "Using Autonegotiation at Half Duplex only\n");
+               adapter->hw.autoneg = 1;
+               adapter->hw.autoneg_advertised = ADVERTISE_10_HALF |
+                                                ADVERTISE_100_HALF;
+               break;
+       case FULL_DUPLEX:
+               printk(KERN_INFO "Full Duplex specified without Speed\n");
+               printk(KERN_INFO "Using Autonegotiation at Full Duplex only\n");
+               adapter->hw.autoneg = 1;
+               adapter->hw.autoneg_advertised = ADVERTISE_10_FULL |
+                                                ADVERTISE_100_FULL |
+                                                ADVERTISE_1000_FULL;
+               break;
+       case SPEED_10:
+               printk(KERN_INFO "10 Mbps Speed specified without Duplex\n");
+               printk(KERN_INFO "Using Autonegotiation at 10 Mbps only\n");
+               adapter->hw.autoneg = 1;
+               adapter->hw.autoneg_advertised = ADVERTISE_10_HALF |
+                                                ADVERTISE_10_FULL;
+               break;
+       case SPEED_10 + HALF_DUPLEX:
+               printk(KERN_INFO "Forcing to 10 Mbps Half Duplex\n");
+               adapter->hw.autoneg = 0;
+               adapter->hw.forced_speed_duplex = e1000_10_half;
+               adapter->hw.autoneg_advertised = 0;
+               break;
+       case SPEED_10 + FULL_DUPLEX:
+               printk(KERN_INFO "Forcing to 10 Mbps Full Duplex\n");
+               adapter->hw.autoneg = 0;
+               adapter->hw.forced_speed_duplex = e1000_10_full;
+               adapter->hw.autoneg_advertised = 0;
+               break;
+       case SPEED_100:
+               printk(KERN_INFO "100 Mbps Speed specified without Duplex\n");
+               printk(KERN_INFO "Using Autonegotiation at 100 Mbps only\n");
+               adapter->hw.autoneg = 1;
+               adapter->hw.autoneg_advertised = ADVERTISE_100_HALF |
+                                                ADVERTISE_100_FULL;
+               break;
+       case SPEED_100 + HALF_DUPLEX:
+               printk(KERN_INFO "Forcing to 100 Mbps Half Duplex\n");
+               adapter->hw.autoneg = 0;
+               adapter->hw.forced_speed_duplex = e1000_100_half;
+               adapter->hw.autoneg_advertised = 0;
+               break;
+       case SPEED_100 + FULL_DUPLEX:
+               printk(KERN_INFO "Forcing to 100 Mbps Full Duplex\n");
+               adapter->hw.autoneg = 0;
+               adapter->hw.forced_speed_duplex = e1000_100_full;
+               adapter->hw.autoneg_advertised = 0;
+               break;
+       case SPEED_1000:
+               printk(KERN_INFO "1000 Mbps Speed specified without Duplex\n");
+               printk(KERN_INFO
+                      "Using Autonegotiation at 1000 Mbps Full Duplex only\n");
+               adapter->hw.autoneg = 1;
+               adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
+               break;
+       case SPEED_1000 + HALF_DUPLEX:
+               printk(KERN_INFO "Half Duplex is not supported at 1000 Mbps\n");
+               printk(KERN_INFO
+                      "Using Autonegotiation at 1000 Mbps Full Duplex only\n");
+               adapter->hw.autoneg = 1;
+               adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
+               break;
+       case SPEED_1000 + FULL_DUPLEX:
+               printk(KERN_INFO
+                      "Using Autonegotiation at 1000 Mbps Full Duplex only\n");
+               adapter->hw.autoneg = 1;
+               adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
+               break;
+       default:
+               BUG();
+       }
+
+       /* Speed, AutoNeg and MDI/MDI-X must all play nice */
+       if (e1000_validate_mdi_setting(&(adapter->hw)) < 0) {
+               printk(KERN_INFO "Speed, AutoNeg and MDI-X specifications are "
+                      "incompatible. Setting MDI-X to a compatible value.\n");
+       }
+}
+
index 3c09f9846af78d259dbf287bb37d592976342bf8..8f0a972dd74500557d3dd744f851d9b2eb80e42c 100644 (file)
@@ -847,6 +847,99 @@ pci_set_master(struct pci_dev *dev)
        pcibios_set_master(dev);
 }
 
+/**
+ * pdev_set_mwi - arch helper function for pcibios_set_mwi
+ * @dev: the PCI device for which MWI is enabled
+ *
+ * Helper function for implementation the arch-specific pcibios_set_mwi
+ * function.  Originally copied from drivers/net/acenic.c.
+ * Copyright 1998-2001 by Jes Sorensen, <jes@trained-monkey.org>.
+ *
+ * RETURNS: An appriopriate -ERRNO error value on eror, or zero for success.
+ */
+int
+pdev_set_mwi(struct pci_dev *dev)
+{
+       int rc = 0;
+       u8 cache_size;
+
+       /*
+        * Looks like this is necessary to deal with on all architectures,
+        * even this %$#%$# N440BX Intel based thing doesn't get it right.
+        * Ie. having two NICs in the machine, one will have the cache
+        * line set at boot time, the other will not.
+        */
+       pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &cache_size);
+       cache_size <<= 2;
+       if (cache_size != SMP_CACHE_BYTES) {
+               printk(KERN_WARNING "PCI: %s PCI cache line size set incorrectly (%i bytes) by BIOS/FW.\n",
+                      dev->slot_name, cache_size);
+               if (cache_size > SMP_CACHE_BYTES) {
+                       printk("PCI: %s cache line size too large - expecting %i.\n", dev->slot_name, SMP_CACHE_BYTES);
+                       rc = -EINVAL;
+               } else {
+                       printk("PCI: %s PCI cache line size corrected to %i.\n", dev->slot_name, SMP_CACHE_BYTES);
+                       pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
+                                             SMP_CACHE_BYTES >> 2);
+               }
+       }
+
+       return rc;
+}
+
+/**
+ * pci_set_mwi - enables memory-write-invalidate PCI transaction
+ * @dev: the PCI device for which MWI is enabled
+ *
+ * Enables the Memory-Write-Invalidate transaction in %PCI_COMMAND,
+ * and then calls @pcibios_set_mwi to do the needed arch specific
+ * operations or a generic mwi-prep function.
+ *
+ * RETURNS: An appriopriate -ERRNO error value on eror, or zero for success.
+ */
+int
+pci_set_mwi(struct pci_dev *dev)
+{
+       int rc;
+       u16 cmd;
+
+#ifdef HAVE_ARCH_PCI_MWI
+       rc = pcibios_set_mwi(dev);
+#else
+       rc = pdev_set_mwi(dev);
+#endif
+
+       if (rc)
+               return rc;
+
+       pci_read_config_word(dev, PCI_COMMAND, &cmd);
+       if (! (cmd & PCI_COMMAND_INVALIDATE)) {
+               DBG("PCI: Enabling Mem-Wr-Inval for device %s\n", dev->slot_name);
+               cmd |= PCI_COMMAND_INVALIDATE;
+               pci_write_config_word(dev, PCI_COMMAND, cmd);
+       }
+       
+       return 0;
+}
+
+/**
+ * pci_clear_mwi - disables Memory-Write-Invalidate for device dev
+ * @dev: the PCI device to disable
+ *
+ * Disables PCI Memory-Write-Invalidate transaction on the device
+ */
+void
+pci_clear_mwi(struct pci_dev *dev)
+{
+       u16 cmd;
+
+       pci_read_config_word(dev, PCI_COMMAND, &cmd);
+       if (cmd & PCI_COMMAND_INVALIDATE) {
+               cmd &= ~PCI_COMMAND_INVALIDATE;
+               pci_write_config_word(dev, PCI_COMMAND, cmd);
+       }
+}
+
 int
 pci_set_dma_mask(struct pci_dev *dev, u64 mask)
 {
index 936e5bc86c863c8f5145b7b9621beb06265ca7e3..41049e71b2268e7c8de935aa71b9a0615809487e 100644 (file)
@@ -9,6 +9,8 @@
 #define SA_INTERRUPT    0x20000000
 #define SA_SHIRQ        0x04000000
 
+#define SA_SAMPLE_RANDOM  0   /* Linux driver compatibility */
+
 #define TIMER_IRQ 0
 
 extern void disable_irq(unsigned int);
index 5b4ba6e9761f39f2208be514f4d53a765dbf0a65..ba19cfb2b37cf44f3dbafc90879eda55654d7377 100644 (file)
@@ -103,12 +103,16 @@ extern void __get_user_4(void);
 
 /* Careful: we have to cast the result to the type of the pointer for sign reasons */
 #define get_user(x,ptr)                                                        \
-({     int __ret_gu,__val_gu;                                          \
+({     int __ret_gu=1,__val_gu;                                                \
        switch(sizeof (*(ptr))) {                                       \
-       case 1:  __get_user_x(1,__ret_gu,__val_gu,ptr); break;          \
-       case 2:  __get_user_x(2,__ret_gu,__val_gu,ptr); break;          \
-       case 4:  __get_user_x(4,__ret_gu,__val_gu,ptr); break;          \
-       default: __get_user_x(X,__ret_gu,__val_gu,ptr); break;          \
+       case 1: __ret_gu=copy_from_user(&__val_gu,ptr,1); break;                        \
+       case 2: __ret_gu=copy_from_user(&__val_gu,ptr,2); break;                 \
+       case 4: __ret_gu=copy_from_user(&__val_gu,ptr,4); break;                 \
+       default: __ret_gu=copy_from_user(&__val_gu,ptr,8); break;                 \
+       /*case 1:  __get_user_x(1,__ret_gu,__val_gu,ptr); break;*/              \
+       /*case 2:  __get_user_x(2,__ret_gu,__val_gu,ptr); break;*/              \
+       /*case 4:  __get_user_x(4,__ret_gu,__val_gu,ptr); break;*/              \
+       /*default: __get_user_x(X,__ret_gu,__val_gu,ptr); break;*/              \
        }                                                               \
        (x) = (__typeof__(*(ptr)))__val_gu;                             \
        __ret_gu;                                                       \
index 9b65fe1187dcb62449f59150082843beca2cb851..e672ac58876789ec8f09e9ec932ecb12a5273341 100644 (file)
@@ -2,8 +2,11 @@
  * ethtool.h: Defines for Linux ethtool.
  *
  * Copyright (C) 1998 David S. Miller (davem@redhat.com)
- * Copyright 2001 Jeff Garzik <jgarzik@mandrakesoft.com>
+ * Copyright 2001 Jeff Garzik <jgarzik@pobox.com>
  * Portions Copyright 2001 Sun Microsystems (thockin@sun.com)
+ * Portions Copyright 2002 Intel (eli.kupermann@intel.com,
+ *                                christopher.leech@intel.com,
+ *                                scott.feldman@intel.com)
  */
 
 #ifndef _LINUX_ETHTOOL_H
@@ -36,7 +39,9 @@ struct ethtool_drvinfo {
        char    bus_info[ETHTOOL_BUSINFO_LEN];  /* Bus info for this IF. */
                                /* For PCI devices, use pci_dev->slot_name. */
        char    reserved1[32];
-       char    reserved2[24];
+       char    reserved2[16];
+       u32     n_stats;        /* number of u64's from ETHTOOL_GSTATS */
+       u32     testinfo_len;
        u32     eedump_len;     /* Size of data from ETHTOOL_GEEPROM (bytes) */
        u32     regdump_len;    /* Size of data from ETHTOOL_GREGS (bytes) */
 };
@@ -72,6 +77,179 @@ struct ethtool_eeprom {
        u32     len; /* in bytes */
        u8      data[0];
 };
+
+/* for configuring coalescing parameters of chip */
+struct ethtool_coalesce {
+       u32     cmd;    /* ETHTOOL_{G,S}COALESCE */
+
+       /* How many usecs to delay an RX interrupt after
+        * a packet arrives.  If 0, only rx_max_coalesced_frames
+        * is used.
+        */
+       u32     rx_coalesce_usecs;
+
+       /* How many packets to delay an RX interrupt after
+        * a packet arrives.  If 0, only rx_coalesce_usecs is
+        * used.  It is illegal to set both usecs and max frames
+        * to zero as this would cause RX interrupts to never be
+        * generated.
+        */
+       u32     rx_max_coalesced_frames;
+
+       /* Same as above two parameters, except that these values
+        * apply while an IRQ is being services by the host.  Not
+        * all cards support this feature and the values are ignored
+        * in that case.
+        */
+       u32     rx_coalesce_usecs_irq;
+       u32     rx_max_coalesced_frames_irq;
+
+       /* How many usecs to delay a TX interrupt after
+        * a packet is sent.  If 0, only tx_max_coalesced_frames
+        * is used.
+        */
+       u32     tx_coalesce_usecs;
+
+       /* How many packets to delay a TX interrupt after
+        * a packet is sent.  If 0, only tx_coalesce_usecs is
+        * used.  It is illegal to set both usecs and max frames
+        * to zero as this would cause TX interrupts to never be
+        * generated.
+        */
+       u32     tx_max_coalesced_frames;
+
+       /* Same as above two parameters, except that these values
+        * apply while an IRQ is being services by the host.  Not
+        * all cards support this feature and the values are ignored
+        * in that case.
+        */
+       u32     tx_coalesce_usecs_irq;
+       u32     tx_max_coalesced_frames_irq;
+
+       /* How many usecs to delay in-memory statistics
+        * block updates.  Some drivers do not have an in-memory
+        * statistic block, and in such cases this value is ignored.
+        * This value must not be zero.
+        */
+       u32     stats_block_coalesce_usecs;
+
+       /* Adaptive RX/TX coalescing is an algorithm implemented by
+        * some drivers to improve latency under low packet rates and
+        * improve throughput under high packet rates.  Some drivers
+        * only implement one of RX or TX adaptive coalescing.  Anything
+        * not implemented by the driver causes these values to be
+        * silently ignored.
+        */
+       u32     use_adaptive_rx_coalesce;
+       u32     use_adaptive_tx_coalesce;
+
+       /* When the packet rate (measured in packets per second)
+        * is below pkt_rate_low, the {rx,tx}_*_low parameters are
+        * used.
+        */
+       u32     pkt_rate_low;
+       u32     rx_coalesce_usecs_low;
+       u32     rx_max_coalesced_frames_low;
+       u32     tx_coalesce_usecs_low;
+       u32     tx_max_coalesced_frames_low;
+
+       /* When the packet rate is below pkt_rate_high but above
+        * pkt_rate_low (both measured in packets per second) the
+        * normal {rx,tx}_* coalescing parameters are used.
+        */
+
+       /* When the packet rate is (measured in packets per second)
+        * is above pkt_rate_high, the {rx,tx}_*_high parameters are
+        * used.
+        */
+       u32     pkt_rate_high;
+       u32     rx_coalesce_usecs_high;
+       u32     rx_max_coalesced_frames_high;
+       u32     tx_coalesce_usecs_high;
+       u32     tx_max_coalesced_frames_high;
+
+       /* How often to do adaptive coalescing packet rate sampling,
+        * measured in seconds.  Must not be zero.
+        */
+       u32     rate_sample_interval;
+};
+
+/* for configuring RX/TX ring parameters */
+struct ethtool_ringparam {
+       u32     cmd;    /* ETHTOOL_{G,S}RINGPARAM */
+
+       /* Read only attributes.  These indicate the maximum number
+        * of pending RX/TX ring entries the driver will allow the
+        * user to set.
+        */
+       u32     rx_max_pending;
+       u32     rx_mini_max_pending;
+       u32     rx_jumbo_max_pending;
+       u32     tx_max_pending;
+
+       /* Values changeable by the user.  The valid values are
+        * in the range 1 to the "*_max_pending" counterpart above.
+        */
+       u32     rx_pending;
+       u32     rx_mini_pending;
+       u32     rx_jumbo_pending;
+       u32     tx_pending;
+};
+
+/* for configuring link flow control parameters */
+struct ethtool_pauseparam {
+       u32     cmd;    /* ETHTOOL_{G,S}PAUSEPARAM */
+
+       /* If the link is being auto-negotiated (via ethtool_cmd.autoneg
+        * being true) the user may set 'autonet' here non-zero to have the
+        * pause parameters be auto-negotiated too.  In such a case, the
+        * {rx,tx}_pause values below determine what capabilities are
+        * advertised.
+        *
+        * If 'autoneg' is zero or the link is not being auto-negotiated,
+        * then {rx,tx}_pause force the driver to use/not-use pause
+        * flow control.
+        */
+       u32     autoneg;
+       u32     rx_pause;
+       u32     tx_pause;
+};
+
+#define ETH_GSTRING_LEN                32
+enum ethtool_stringset {
+       ETH_SS_TEST             = 0,
+       ETH_SS_STATS,
+};
+
+/* for passing string sets for data tagging */
+struct ethtool_gstrings {
+       u32     cmd;            /* ETHTOOL_GSTRINGS */
+       u32     string_set;     /* string set id e.c. ETH_SS_TEST, etc*/
+       u32     len;            /* number of strings in the string set */
+       u8      data[0];
+};
+
+enum ethtool_test_flags {
+       ETH_TEST_FL_OFFLINE     = (1 << 0),     /* online / offline */
+       ETH_TEST_FL_FAILED      = (1 << 1),     /* test passed / failed */
+};
+
+/* for requesting NIC test and getting results*/
+struct ethtool_test {
+       u32     cmd;            /* ETHTOOL_TEST */
+       u32     flags;          /* ETH_TEST_FL_xxx */
+       u32     reserved;
+       u32     len;            /* result length, in number of u64 elements */
+       u64     data[0];
+};
+
+/* for dumping NIC-specific statistics */
+struct ethtool_stats {
+       u32     cmd;            /* ETHTOOL_GSTATS */
+       u32     n_stats;        /* number of u64's being returned */
+       u64     data[0];
+};
+
 /* CMDs currently supported */
 #define ETHTOOL_GSET           0x00000001 /* Get settings. */
 #define ETHTOOL_SSET           0x00000002 /* Set settings, privileged. */
@@ -82,9 +260,27 @@ struct ethtool_eeprom {
 #define ETHTOOL_GMSGLVL                0x00000007 /* Get driver message level */
 #define ETHTOOL_SMSGLVL                0x00000008 /* Set driver msg level, priv. */
 #define ETHTOOL_NWAY_RST       0x00000009 /* Restart autonegotiation, priv. */
-#define ETHTOOL_GLINK          0x0000000a /* Get link status */
+#define ETHTOOL_GLINK          0x0000000a /* Get link status (ethtool_value) */
 #define ETHTOOL_GEEPROM                0x0000000b /* Get EEPROM data */
-#define ETHTOOL_SEEPROM                0x0000000c /* Set EEPROM data */
+#define ETHTOOL_SEEPROM                0x0000000c /* Set EEPROM data, priv. */
+#define ETHTOOL_GCOALESCE      0x0000000e /* Get coalesce config */
+#define ETHTOOL_SCOALESCE      0x0000000f /* Set coalesce config, priv. */
+#define ETHTOOL_GRINGPARAM     0x00000010 /* Get ring parameters */
+#define ETHTOOL_SRINGPARAM     0x00000011 /* Set ring parameters, priv. */
+#define ETHTOOL_GPAUSEPARAM    0x00000012 /* Get pause parameters */
+#define ETHTOOL_SPAUSEPARAM    0x00000013 /* Set pause parameters, priv. */
+#define ETHTOOL_GRXCSUM                0x00000014 /* Get RX hw csum enable (ethtool_value) */
+#define ETHTOOL_SRXCSUM                0x00000015 /* Set RX hw csum enable (ethtool_value) */
+#define ETHTOOL_GTXCSUM                0x00000016 /* Get TX hw csum enable (ethtool_value) */
+#define ETHTOOL_STXCSUM                0x00000017 /* Set TX hw csum enable (ethtool_value) */
+#define ETHTOOL_GSG            0x00000018 /* Get scatter-gather enable
+                                           * (ethtool_value) */
+#define ETHTOOL_SSG            0x00000019 /* Set scatter-gather enable
+                                           * (ethtool_value), priv. */
+#define ETHTOOL_TEST           0x0000001a /* execute NIC self-test, priv. */
+#define ETHTOOL_GSTRINGS       0x0000001b /* get specified string set */
+#define ETHTOOL_PHYS_ID                0x0000001c /* identify the NIC */
+#define ETHTOOL_GSTATS         0x0000001d /* get NIC-specific statistics */
 
 /* compatibility with older code */
 #define SPARC_ETH_GSET         ETHTOOL_GSET
diff --git a/xen-2.4.16/include/xeno/if_vlan.h b/xen-2.4.16/include/xeno/if_vlan.h
new file mode 100644 (file)
index 0000000..aa9fb49
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * VLAN                An implementation of 802.1Q VLAN tagging.
+ *
+ * Authors:    Ben Greear <greearb@candelatech.com>
+ *
+ *             This program is free software; you can redistribute it and/or
+ *             modify it under the terms of the GNU General Public License
+ *             as published by the Free Software Foundation; either version
+ *             2 of the License, or (at your option) any later version.
+ *
+ */
+
+#ifndef _LINUX_IF_VLAN_H_
+#define _LINUX_IF_VLAN_H_
+
+#ifdef __KERNEL__
+
+/* externally defined structs */
+struct vlan_group;
+struct net_device;
+struct sk_buff;
+struct packet_type;
+struct vlan_collection;
+struct vlan_dev_info;
+
+//#include <linux/proc_fs.h> /* for proc_dir_entry */
+#include <linux/netdevice.h>
+
+#define VLAN_HLEN      4               /* The additional bytes (on top of the Ethernet header)
+                                        * that VLAN requires.
+                                        */
+#define VLAN_ETH_ALEN  6               /* Octets in one ethernet addr   */
+#define VLAN_ETH_HLEN  18              /* Total octets in header.       */
+#define VLAN_ETH_ZLEN  64              /* Min. octets in frame sans FCS */
+
+/*
+ * According to 802.3ac, the packet can be 4 bytes longer. --Klika Jan
+ */
+#define VLAN_ETH_DATA_LEN      1500    /* Max. octets in payload        */
+#define VLAN_ETH_FRAME_LEN     1518    /* Max. octets in frame sans FCS */
+
+struct vlan_ethhdr {
+   unsigned char       h_dest[ETH_ALEN];          /* destination eth addr      */
+   unsigned char       h_source[ETH_ALEN];        /* source ether addr */
+   unsigned short       h_vlan_proto;              /* Should always be 0x8100 */
+   unsigned short       h_vlan_TCI;                /* Encapsulates priority and VLAN ID */
+   unsigned short      h_vlan_encapsulated_proto; /* packet type ID field (or len) */
+};
+
+struct vlan_hdr {
+   unsigned short       h_vlan_TCI;                /* Encapsulates priority and VLAN ID */
+   unsigned short       h_vlan_encapsulated_proto; /* packet type ID field (or len) */
+};
+
+#define VLAN_VID_MASK  0xfff
+
+/* found in af_inet.c */
+extern int (*vlan_ioctl_hook)(unsigned long arg);
+
+#define VLAN_NAME "vlan"
+
+/* if this changes, algorithm will have to be reworked because this
+ * depends on completely exhausting the VLAN identifier space.  Thus
+ * it gives constant time look-up, but in many cases it wastes memory.
+ */
+#define VLAN_GROUP_ARRAY_LEN 4096
+
+struct vlan_group {
+       int real_dev_ifindex; /* The ifindex of the ethernet(like) device the vlan is attached to. */
+       struct net_device *vlan_devices[VLAN_GROUP_ARRAY_LEN];
+
+       struct vlan_group *next; /* the next in the list */
+};
+
+struct vlan_priority_tci_mapping {
+       unsigned long priority;
+       unsigned short vlan_qos; /* This should be shifted when first set, so we only do it
+                                 * at provisioning time.
+                                 * ((skb->priority << 13) & 0xE000)
+                                 */
+       struct vlan_priority_tci_mapping *next;
+};
+
+/* Holds information that makes sense if this device is a VLAN device. */
+struct vlan_dev_info {
+       /** This will be the mapping that correlates skb->priority to
+        * 3 bits of VLAN QOS tags...
+        */
+       unsigned long ingress_priority_map[8];
+       struct vlan_priority_tci_mapping *egress_priority_map[16]; /* hash table */
+
+       unsigned short vlan_id;        /*  The VLAN Identifier for this interface. */
+       unsigned short flags;          /* (1 << 0) re_order_header   This option will cause the
+                                        *   VLAN code to move around the ethernet header on
+                                        *   ingress to make the skb look **exactly** like it
+                                        *   came in from an ethernet port.  This destroys some of
+                                        *   the VLAN information in the skb, but it fixes programs
+                                        *   like DHCP that use packet-filtering and don't understand
+                                        *   802.1Q
+                                        */
+       struct dev_mc_list *old_mc_list;  /* old multi-cast list for the VLAN interface..
+                                           * we save this so we can tell what changes were
+                                           * made, in order to feed the right changes down
+                                           * to the real hardware...
+                                           */
+       int old_allmulti;               /* similar to above. */
+       int old_promiscuity;            /* similar to above. */
+       struct net_device *real_dev;    /* the underlying device/interface */
+       struct proc_dir_entry *dent;    /* Holds the proc data */
+       unsigned long cnt_inc_headroom_on_tx; /* How many times did we have to grow the skb on TX. */
+       unsigned long cnt_encap_on_xmit;      /* How many times did we have to encapsulate the skb on TX. */
+       struct net_device_stats dev_stats; /* Device stats (rx-bytes, tx-pkts, etc...) */
+};
+
+#define VLAN_DEV_INFO(x) ((struct vlan_dev_info *)(x->priv))
+
+/* inline functions */
+
+static inline struct net_device_stats *vlan_dev_get_stats(struct net_device *dev)
+{
+       return &(VLAN_DEV_INFO(dev)->dev_stats);
+}
+
+static inline __u32 vlan_get_ingress_priority(struct net_device *dev,
+                                             unsigned short vlan_tag)
+{
+       struct vlan_dev_info *vip = VLAN_DEV_INFO(dev);
+
+       return vip->ingress_priority_map[(vlan_tag >> 13) & 0x7];
+}
+
+/* VLAN tx hw acceleration helpers. */
+struct vlan_skb_tx_cookie {
+       u32     magic;
+       u32     vlan_tag;
+};
+
+#define VLAN_TX_COOKIE_MAGIC   0x564c414e      /* "VLAN" in ascii. */
+#define VLAN_TX_SKB_CB(__skb)  ((struct vlan_skb_tx_cookie *)&((__skb)->cb[0]))
+#define vlan_tx_tag_present(__skb) \
+       (VLAN_TX_SKB_CB(__skb)->magic == VLAN_TX_COOKIE_MAGIC)
+#define vlan_tx_tag_get(__skb) (VLAN_TX_SKB_CB(__skb)->vlan_tag)
+
+/* VLAN rx hw acceleration helper.  This acts like netif_{rx,receive_skb}(). */
+static inline int __vlan_hwaccel_rx(struct sk_buff *skb,
+                                   struct vlan_group *grp,
+                                   unsigned short vlan_tag, int polling)
+{
+       struct net_device_stats *stats;
+
+       skb->dev = grp->vlan_devices[vlan_tag & VLAN_VID_MASK];
+       if (skb->dev == NULL) {
+               kfree_skb(skb);
+
+               /* Not NET_RX_DROP, this is not being dropped
+                * due to congestion.
+                */
+               return 0;
+       }
+
+       skb->dev->last_rx = jiffies;
+
+       stats = vlan_dev_get_stats(skb->dev);
+       stats->rx_packets++;
+       stats->rx_bytes += skb->len;
+
+       skb->priority = vlan_get_ingress_priority(skb->dev, vlan_tag);
+       switch (skb->pkt_type) {
+       case PACKET_BROADCAST:
+               break;
+
+       case PACKET_MULTICAST:
+               stats->multicast++;
+               break;
+
+       case PACKET_OTHERHOST:
+               /* Our lower layer thinks this is not local, let's make sure.
+                * This allows the VLAN to have a different MAC than the underlying
+                * device, and still route correctly.
+                */
+               if (!memcmp(skb->mac.ethernet->h_dest, skb->dev->dev_addr, ETH_ALEN))
+                       skb->pkt_type = PACKET_HOST;
+               break;
+       };
+
+       return (polling ? netif_receive_skb(skb) : netif_rx(skb));
+}
+
+static inline int vlan_hwaccel_rx(struct sk_buff *skb,
+                                 struct vlan_group *grp,
+                                 unsigned short vlan_tag)
+{
+       return __vlan_hwaccel_rx(skb, grp, vlan_tag, 0);
+}
+
+static inline int vlan_hwaccel_receive_skb(struct sk_buff *skb,
+                                          struct vlan_group *grp,
+                                          unsigned short vlan_tag)
+{
+       return __vlan_hwaccel_rx(skb, grp, vlan_tag, 1);
+}
+#endif /* __KERNEL__ */
+
+/* VLAN IOCTLs are found in sockios.h */
+
+/* Passed in vlan_ioctl_args structure to determine behaviour. */
+enum vlan_ioctl_cmds {
+       ADD_VLAN_CMD,
+       DEL_VLAN_CMD,
+       SET_VLAN_INGRESS_PRIORITY_CMD,
+       SET_VLAN_EGRESS_PRIORITY_CMD,
+       GET_VLAN_INGRESS_PRIORITY_CMD,
+       GET_VLAN_EGRESS_PRIORITY_CMD,
+       SET_VLAN_NAME_TYPE_CMD,
+       SET_VLAN_FLAG_CMD
+};
+
+enum vlan_name_types {
+       VLAN_NAME_TYPE_PLUS_VID, /* Name will look like:  vlan0005 */
+       VLAN_NAME_TYPE_RAW_PLUS_VID, /* name will look like:  eth1.0005 */
+       VLAN_NAME_TYPE_PLUS_VID_NO_PAD, /* Name will look like:  vlan5 */
+       VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD, /* Name will look like:  eth0.5 */
+       VLAN_NAME_TYPE_HIGHEST
+};
+
+struct vlan_ioctl_args {
+       int cmd; /* Should be one of the vlan_ioctl_cmds enum above. */
+       char device1[24];
+
+        union {
+               char device2[24];
+               int VID;
+               unsigned int skb_priority;
+               unsigned int name_type;
+               unsigned int bind_type;
+               unsigned int flag; /* Matches vlan_dev_info flags */
+        } u;
+
+       short vlan_qos;   
+};
+
+#endif /* !(_LINUX_IF_VLAN_H_) */
diff --git a/xen-2.4.16/include/xeno/kernel.h b/xen-2.4.16/include/xeno/kernel.h
new file mode 100644 (file)
index 0000000..993a6c1
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef _LINUX_KERNEL_H
+#define _LINUX_KERNEL_H
+
+/*
+ * 'kernel.h' contains some often-used function prototypes etc
+ */
+
+/*
+ * min()/max() macros that also do
+ * strict type-checking.. See the
+ * "unnecessary" pointer comparison.
+ */
+#define min(x,y) ({ \
+        const typeof(x) _x = (x);       \
+        const typeof(y) _y = (y);       \
+        (void) (&_x == &_y);            \
+        _x < _y ? _x : _y; })
+
+#define max(x,y) ({ \
+        const typeof(x) _x = (x);       \
+        const typeof(y) _y = (y);       \
+        (void) (&_x == &_y);            \
+        _x > _y ? _x : _y; })
+
+/*
+ * ..and if you can't take the strict
+ * types, you can specify one yourself.
+ *
+ * Or not use min/max at all, of course.
+ */
+#define min_t(type,x,y) \
+        ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
+#define max_t(type,x,y) \
+        ({ type __x = (x); type __y = (y); __x > __y ? __x: __y; })
+
+#endif /* _LINUX_KERNEL_H */
+
index 51b063a726b72f037b2db3b0a777a6fd7f56f57f..f56238bdef6397b9e4ad37dc64a90694a1be24f3 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/config.h>
 
 struct divert_blk;
+struct vlan_group;
 
 #define HAVE_ALLOC_NETDEV              /* feature macro: alloc_xxxdev
                                           functions are available. */
@@ -311,6 +312,12 @@ struct net_device
        void                    *ip6_ptr;       /* IPv6 specific data */
        void                    *ec_ptr;        /* Econet specific data */
 
+                                               /* IAP: add fields but
+                                               nothing else */         
+       struct list_head        poll_list;      /* Link to poll list    */
+       int                     quota;
+       int                     weight;
+
        struct Qdisc            *qdisc;
        struct Qdisc            *qdisc_sleeping;
        struct Qdisc            *qdisc_list;
@@ -339,6 +346,10 @@ struct net_device
 #define NETIF_F_DYNALLOC       16      /* Self-dectructable device. */
 #define NETIF_F_HIGHDMA                32      /* Can DMA to high memory. */
 #define NETIF_F_FRAGLIST       64      /* Scatter/gather IO. */
+#define NETIF_F_HW_VLAN_TX      128     /* Transmit VLAN hw acceleration */
+#define NETIF_F_HW_VLAN_RX      256     /* Receive VLAN hw acceleration */
+#define NETIF_F_HW_VLAN_FILTER  512     /* Receive filtering on VLAN */
+#define NETIF_F_VLAN_CHALLENGED 1024    /* Device cannot handle VLAN packets */
 
        /* Called after device is detached from network. */
        void                    (*uninit)(struct net_device *dev);
@@ -350,6 +361,7 @@ struct net_device
        int                     (*stop)(struct net_device *dev);
        int                     (*hard_start_xmit) (struct sk_buff *skb,
                                                    struct net_device *dev);
+       int                     (*poll) (struct net_device *dev, int *quota); /* XXX IAP */
        int                     (*hard_header) (struct sk_buff *skb,
                                                struct net_device *dev,
                                                unsigned short type,
@@ -380,6 +392,13 @@ struct net_device
 #define HAVE_TX_TIMEOUT
        void                    (*tx_timeout) (struct net_device *dev);
 
+        void                    (*vlan_rx_register)(struct net_device *dev,
+                                                    struct vlan_group *grp);
+        void                    (*vlan_rx_add_vid)(struct net_device *dev,
+                                                   unsigned short vid);
+        void                    (*vlan_rx_kill_vid)(struct net_device *dev,
+                                                    unsigned short vid);
+
        int                     (*hard_header_parse)(struct sk_buff *skb,
                                                     unsigned char *haddr);
        int                     (*neigh_setup)(struct net_device *dev, struct neigh_parms *);
diff --git a/xen-2.4.16/include/xeno/notifier.h b/xen-2.4.16/include/xeno/notifier.h
new file mode 100644 (file)
index 0000000..0db9736
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ *     Routines to manage notifier chains for passing status changes to any
+ *     interested routines. We need this instead of hard coded call lists so
+ *     that modules can poke their nose into the innards. The network devices
+ *     needed them so here they are for the rest of you.
+ *
+ *                             Alan Cox <Alan.Cox@linux.org>
+ */
+#ifndef _LINUX_NOTIFIER_H
+#define _LINUX_NOTIFIER_H
+#include <linux/errno.h>
+
+struct notifier_block
+{
+       int (*notifier_call)(struct notifier_block *self, unsigned long, void *);
+       struct notifier_block *next;
+       int priority;
+};
+
+
+#ifdef __KERNEL__
+
+extern int notifier_chain_register(struct notifier_block **list, struct notifier_block *n);
+extern int notifier_chain_unregister(struct notifier_block **nl, struct notifier_block *n);
+extern int notifier_call_chain(struct notifier_block **n, unsigned long val, void *v);
+
+#define NOTIFY_DONE            0x0000          /* Don't care */
+#define NOTIFY_OK              0x0001          /* Suits me */
+#define NOTIFY_STOP_MASK       0x8000          /* Don't call further */
+#define NOTIFY_BAD             (NOTIFY_STOP_MASK|0x0002)       /* Bad/Veto action      */
+
+/*
+ *     Declared notifiers so far. I can imagine quite a few more chains
+ *     over time (eg laptop power reset chains, reboot chain (to clean 
+ *     device units up), device [un]mount chain, module load/unload chain,
+ *     low memory chain, screenblank chain (for plug in modular screenblankers) 
+ *     VC switch chains (for loadable kernel svgalib VC switch helpers) etc...
+ */
+/* netdevice notifier chain */
+#define NETDEV_UP      0x0001  /* For now you can't veto a device up/down */
+#define NETDEV_DOWN    0x0002
+#define NETDEV_REBOOT  0x0003  /* Tell a protocol stack a network interface
+                                  detected a hardware crash and restarted
+                                  - we can use this eg to kick tcp sessions
+                                  once done */
+#define NETDEV_CHANGE  0x0004  /* Notify device state change */
+#define NETDEV_REGISTER 0x0005
+#define NETDEV_UNREGISTER      0x0006
+#define NETDEV_CHANGEMTU       0x0007
+#define NETDEV_CHANGEADDR      0x0008
+#define NETDEV_GOING_DOWN      0x0009
+#define NETDEV_CHANGENAME      0x000A
+
+#define SYS_DOWN       0x0001  /* Notify of system down */
+#define SYS_RESTART    SYS_DOWN
+#define SYS_HALT       0x0002  /* Notify of system halt */
+#define SYS_POWER_OFF  0x0003  /* Notify of system power off */
+
+#define NETLINK_URELEASE       0x0001  /* Unicast netlink socket released */
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_NOTIFIER_H */
index 15e51d2cdb73fd1135ac7081d6232f9c0d32a6c5..d477afeb4b7daaa60ea284d3314c0d60394e01c0 100644 (file)
@@ -561,6 +561,10 @@ int pci_write_config_dword(struct pci_dev *dev, int where, u32 val);
 int pci_enable_device(struct pci_dev *dev);
 void pci_disable_device(struct pci_dev *dev);
 void pci_set_master(struct pci_dev *dev);
+#define HAVE_PCI_SET_MWI
+int pci_set_mwi(struct pci_dev *dev);
+void pci_clear_mwi(struct pci_dev *dev);
+int pdev_set_mwi(struct pci_dev *dev);
 int pci_set_dma_mask(struct pci_dev *dev, u64 mask);
 int pci_dac_set_dma_mask(struct pci_dev *dev, u64 mask);
 int pci_assign_resource(struct pci_dev *dev, int i);
diff --git a/xen-2.4.16/include/xeno/reboot.h b/xen-2.4.16/include/xeno/reboot.h
new file mode 100644 (file)
index 0000000..5f128a9
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef _LINUX_REBOOT_H
+#define _LINUX_REBOOT_H
+
+/*
+ * Magic values required to use _reboot() system call.
+ */
+
+#define        LINUX_REBOOT_MAGIC1     0xfee1dead
+#define        LINUX_REBOOT_MAGIC2     672274793
+#define        LINUX_REBOOT_MAGIC2A    85072278
+#define        LINUX_REBOOT_MAGIC2B    369367448
+
+
+/*
+ * Commands accepted by the _reboot() system call.
+ *
+ * RESTART     Restart system using default command and mode.
+ * HALT        Stop OS and give system control to ROM monitor, if any.
+ * CAD_ON      Ctrl-Alt-Del sequence causes RESTART command.
+ * CAD_OFF     Ctrl-Alt-Del sequence sends SIGINT to init task.
+ * POWER_OFF   Stop OS and remove all power from system, if possible.
+ * RESTART2    Restart system using given command string.
+ */
+
+#define        LINUX_REBOOT_CMD_RESTART        0x01234567
+#define        LINUX_REBOOT_CMD_HALT           0xCDEF0123
+#define        LINUX_REBOOT_CMD_CAD_ON         0x89ABCDEF
+#define        LINUX_REBOOT_CMD_CAD_OFF        0x00000000
+#define        LINUX_REBOOT_CMD_POWER_OFF      0x4321FEDC
+#define        LINUX_REBOOT_CMD_RESTART2       0xA1B2C3D4
+
+
+#ifdef __KERNEL__
+
+#include <linux/notifier.h>
+
+extern int register_reboot_notifier(struct notifier_block *);
+extern int unregister_reboot_notifier(struct notifier_block *);
+
+
+/*
+ * Architecture-specific implementations of sys_reboot commands.
+ */
+
+extern void machine_restart(char *cmd);
+extern void machine_halt(void);
+extern void machine_power_off(void);
+
+#endif
+
+#endif /* _LINUX_REBOOT_H */
index 6a270f3f0c8784d673a613bbc4a2a67d6f0bfdbb..c5f8d5586d307aab56042863cf5028660c5cc611 100644 (file)
@@ -28,4 +28,23 @@ typedef unsigned short          ushort;
 typedef unsigned int            uint;
 typedef unsigned long           ulong;
 
+#ifndef __BIT_TYPES_DEFINED__
+#define __BIT_TYPES_DEFINED__
+
+typedef         __u8            u_int8_t;
+typedef         __s8            int8_t;
+typedef         __u16           u_int16_t;
+typedef         __s16           int16_t;
+typedef         __u32           u_int32_t;
+typedef         __s32           int32_t;
+
+#endif /* !(__BIT_TYPES_DEFINED__) */
+
+typedef         __u8            uint8_t;
+typedef         __u16           uint16_t;
+typedef         __u32           uint32_t;
+typedef         __u64           uint64_t;
+
+
+
 #endif /* __TYPES_H__ */